Java tutorial
/* * Copyright 2013 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.docbrowser; import annis.gui.AnnisUI; import annis.libgui.Background; import annis.libgui.Helper; import annis.libgui.PluginSystem; import annis.libgui.visualizers.FilteringVisualizerPlugin; import annis.libgui.visualizers.VisualizerInput; import annis.libgui.visualizers.VisualizerPlugin; import annis.service.objects.CorpusConfig; import annis.service.objects.RawTextWrapper; import annis.service.objects.Visualizer; import com.google.common.base.Joiner; import com.google.common.escape.Escaper; import com.google.common.net.UrlEscapers; import com.sun.jersey.api.client.WebResource; import com.vaadin.server.ClientConnector; import com.vaadin.server.FontAwesome; import com.vaadin.server.Resource; import com.vaadin.server.Sizeable.Unit; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.Panel; import com.vaadin.ui.ProgressBar; import com.vaadin.ui.TabSheet; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.corpus_tools.salt.common.SDocument; import org.corpus_tools.salt.common.SaltProject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents a global controller for the doc browser feature. * * @author Benjamin Weienfels <b.pixeldrama@gmail.com> */ public class DocBrowserController implements Serializable { private final Logger log = LoggerFactory.getLogger(DocBrowserController.class); // holds the complete state of the gui private final AnnisUI ui; // track the already initiated doc browsers private final Map<String, Component> initedDocBrowsers; // cache for already initiated visualizations, the key is the doc name private final Map<String, Component> initiatedVis; // keep track of already visible doc visualizer, so it easy to switch to them. private final Map<String, Panel> visibleVisHolder; private static final Resource EYE_ICON = FontAwesome.EYE; private static final Resource DOC_ICON = FontAwesome.FILE_TEXT_O; private final static Escaper urlPathEscape = UrlEscapers.urlPathSegmentEscaper(); public DocBrowserController(AnnisUI ui) { this.ui = ui; this.initedDocBrowsers = new HashMap<>(); this.initiatedVis = new HashMap<>(); this.visibleVisHolder = new HashMap<>(); } public void openDocVis(String corpus, String doc, Visualizer visConfig, Button btn) { final String canonicalTitle = corpus + " > " + doc + " - " + "Visualizer: " + visConfig.getDisplayName(); final String tabCaption = StringUtils.substring(canonicalTitle, 0, 15) + "..."; if (visibleVisHolder.containsKey(canonicalTitle)) { Panel visHolder = visibleVisHolder.get(canonicalTitle); ui.getSearchView().getTabSheet().setSelectedTab(visHolder); return; } Panel visHolder = new Panel(); visHolder.setSizeFull(); visHolder.addDetachListener(new ClientConnector.DetachListener() { @Override public void detach(ClientConnector.DetachEvent event) { visibleVisHolder.remove(canonicalTitle); } }); // first set loading indicator ProgressBar progressBar = new ProgressBar(1.0f); progressBar.setIndeterminate(true); progressBar.setSizeFull(); VerticalLayout layoutProgress = new VerticalLayout(progressBar); layoutProgress.setSizeFull(); layoutProgress.setComponentAlignment(progressBar, Alignment.MIDDLE_CENTER); visHolder.setContent(layoutProgress); Tab visTab = ui.getSearchView().getTabSheet().addTab(visHolder, tabCaption); visTab.setDescription(canonicalTitle); visTab.setIcon(EYE_ICON); visTab.setClosable(true); ui.getSearchView().getTabSheet().setSelectedTab(visTab); // register visible visHolder this.visibleVisHolder.put(canonicalTitle, visHolder); Background.run(new DocVisualizerFetcher(corpus, doc, canonicalTitle, visConfig.getType(), visHolder, visConfig, btn, UI.getCurrent())); } public void openDocBrowser(String corpus) { // if not already init, do it now if (!initedDocBrowsers.containsKey(corpus)) { DocBrowserPanel docBrowser = DocBrowserPanel.initDocBrowserPanel(ui, corpus); initedDocBrowsers.put(corpus, docBrowser); } // init tab and put to front TabSheet.Tab tab = ui.getSearchView().getTabSheet().addTab(initedDocBrowsers.get(corpus), corpus); tab.setIcon(DOC_ICON); tab.setClosable(true); ui.getSearchView().getTabSheet().setSelectedTab(tab); } /** * Creates the input. It only takes the salt project or the raw text from the * text table, never both, since the increase the performance for large texts. * * @param corpus the name of the toplevel corpus * @param docName the name of the document * @param config the visualizer configuration * @param isUsingRawText indicates, whether the text from text table is taken, * or if the salt project is traversed. * @param nodeAnnoFilter A list of node annotation names for filtering the nodes or null if no filtering should be applied. * @return a {@link VisualizerInput} input, which is usable for rendering the * whole document. */ public static VisualizerInput createInput(String corpus, String docName, Visualizer config, boolean isUsingRawText, List<String> nodeAnnoFilter) { VisualizerInput input = new VisualizerInput(); // set mappings and namespaces. some visualizer do not survive without input.setMappings(parseMappings(config)); input.setNamespace(config.getNamespace()); String encodedToplevelCorpus = urlPathEscape.escape(corpus); String encodedDocument = urlPathEscape.escape(docName); if (isUsingRawText) { WebResource w = Helper.getAnnisWebResource(); w = w.path("query").path("rawtext").path(encodedToplevelCorpus).path(encodedDocument); RawTextWrapper rawTextWrapper = w.get(RawTextWrapper.class); input.setRawText(rawTextWrapper); } else { // get the whole document wrapped in a salt project SaltProject txt = null; WebResource res = Helper.getAnnisWebResource().path("query").path("graph").path(encodedToplevelCorpus) .path(encodedDocument); if (nodeAnnoFilter != null) { res = res.queryParam("filternodeanno", Joiner.on(",").join(nodeAnnoFilter)); } txt = res.get(SaltProject.class); if (txt != null) { SDocument sDoc = txt.getCorpusGraphs().get(0).getDocuments().get(0); input.setResult(sDoc); } } return input; } private static Properties parseMappings(Visualizer config) { Properties mappings = new Properties(); if (config.getMappings() != null) { // split the entrys String[] entries = config.getMappings().split(";"); for (String e : entries) { // split key-value String[] keyvalue = e.split(":", 2); if (keyvalue.length == 2) { mappings.put(keyvalue[0].trim(), keyvalue[1].trim()); } } } return mappings; } private class DocVisualizerFetcher implements Runnable { Visualizer config; String corpus; String doc; final Button btn; private final String canonicalTitle; private final String type; private final Panel visHolder; private VisualizerInput input; public DocVisualizerFetcher(String corpus, String doc, String canonicalTitle, String type, Panel visHolder, Visualizer config, Button btn, final UI ui) { this.corpus = corpus; this.doc = doc; this.btn = btn; this.config = config; this.canonicalTitle = canonicalTitle; this.type = type; this.visHolder = visHolder; } @Override public void run() { input = null; final boolean createVis = !initiatedVis.containsKey(canonicalTitle); final VisualizerPlugin visualizer = ((PluginSystem) ui).getVisualizer(type); List<String> nodeAnnoFilter = null; if (visualizer instanceof FilteringVisualizerPlugin) { nodeAnnoFilter = ((FilteringVisualizerPlugin) visualizer).getFilteredNodeAnnotationNames(corpus, doc, parseMappings(config)); } // check if a visualization is already initiated { if (createVis) { // fetch the salt project - so long part input = createInput(corpus, doc, config, visualizer.isUsingRawText(), nodeAnnoFilter); } } // after initializing the visualizer update the gui ui.access(new Runnable() { @Override public void run() { btn.setEnabled(true); if (createVis && input != null) { // create and format visualizer Component vis = visualizer.createComponent(input, null); vis.addStyleName(Helper.CORPUS_FONT_FORCE); vis.setPrimaryStyleName("docviewer"); vis.setCaption(canonicalTitle); vis.setWidth(100, Unit.PERCENTAGE); vis.setHeight(-1, Unit.PIXELS); // update visualizer memory cache initiatedVis.put(canonicalTitle, vis); } Component vis = initiatedVis.get(canonicalTitle); visHolder.setContent(vis); } }); } } public boolean docsAvailable(String id) { if (ui != null) { CorpusConfig corpusConfig = ui.getCorpusConfigWithCache(id); if (corpusConfig != null) { if (corpusConfig.containsKey("browse-documents")) { return Boolean.parseBoolean(corpusConfig.getConfig("browse-documents")); } // get the default config else { corpusConfig = ui.getCorpusConfigWithCache(Helper.DEFAULT_CONFIG); boolean browseDocuments = Boolean .parseBoolean(corpusConfig.getConfig("browse-documents", "true")); return browseDocuments; } } } return true; } }