View Javadoc
1   /*
2    * Copyright 2013-2023 Medical Information Systems Research Group (https://medical.zcu.cz),
3    * Department of Computer Science and Engineering, University of West Bohemia.
4    * Address: Univerzitni 8, 306 14 Plzen, Czech Republic.
5    *
6    * This file is part of Sparkle project.
7    *
8    * Sparkle is free software: you can redistribute it and/or modify
9    * it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License.
11   *
12   * Sparkle is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with Sparkle. If not, see <http://www.gnu.org/licenses/>.
19   */
20  package cz.zcu.mre.sparkle.gui.query.queryTypes.describe;
21  
22  import cz.zcu.mre.sparkle.Messages;
23  import cz.zcu.mre.sparkle.data.DataAgent;
24  import cz.zcu.mre.sparkle.data.Storage;
25  import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
26  import cz.zcu.mre.sparkle.gui.query.CustomTitledPane;
27  import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
28  import cz.zcu.mre.sparkle.gui.query.modifiers.LimitOffsetClausePane;
29  import cz.zcu.mre.sparkle.gui.query.modifiers.OrderByClausePane;
30  import cz.zcu.mre.sparkle.gui.query.modifiers.ValuesClausePane;
31  import cz.zcu.mre.sparkle.gui.query.modifiers.groupBy.GroupByClausePane;
32  import cz.zcu.mre.sparkle.gui.query.modifiers.having.HavingClausePane;
33  import cz.zcu.mre.sparkle.gui.query.queryMainParts.FromClausePane;
34  import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
35  import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
36  import cz.zcu.mre.sparkle.tools.Saveable;
37  import cz.zcu.mre.sparkle.tools.SparqlParser;
38  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserNode;
39  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserWhereClauseWalker;
40  import cz.zcu.mre.sparkle.tools.sparqlValidation.SparqlValidationUtils;
41  import javafx.collections.FXCollections;
42  import javafx.collections.ObservableList;
43  import javafx.collections.ObservableSet;
44  import javafx.scene.Node;
45  import org.antlr.v4.runtime.tree.ParseTree;
46  import org.apache.jena.rdf.model.Model;
47  import org.w3c.dom.Element;
48  import java.util.ArrayList;
49  import java.util.List;
50  import java.util.Set;
51  import java.util.Stack;
52  import static cz.zcu.mre.sparkle.gui.query.QueryFormPane.QUERY_PARTS.*;
53  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.getTreeChild;
54  
55  /**
56   * Kontroler panelu s dotazem typu DESCRIBE.
57   *
58   * @author Jan Smucr
59   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
60   */
61  public final class DescribeQueryFormPane extends QueryFormPane<Model> {
62  
63      public static final String XML_QUERY_TYPE_VALUE = "describe"; //$NON-NLS-1$
64  
65      private List<Object> queryFormParts;
66  
67      private ObservableSet<String> describeClauseVariables;
68      private ObservableSet<String> whereClauseVariables;
69      private ObservableSet<String> orderByClauseVariables;
70      private ObservableSet<String> groupByClauseVariables;
71      private ObservableSet<String> valuesClauseVariables;
72  
73      public DescribeQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
74              String paneType) {
75  
76          super(mainForm, dataAgent, localStorage, paneType);
77      }
78  
79      public DescribeQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
80              final Object root, String paneType) throws LoadException {
81  
82          super(mainForm, dataAgent, localStorage, root, paneType);
83      }
84  
85      @Override
86      public final void load(final Object root) throws LoadException {
87          describeClauseVariables = FXCollections.observableSet();
88          whereClauseVariables = FXCollections.observableSet();
89          orderByClauseVariables = FXCollections.observableSet();
90          groupByClauseVariables = FXCollections.observableSet();
91          valuesClauseVariables = FXCollections.observableSet();
92  
93          initializeQueryFormParts();
94          addVariablesCollectors();
95          addPartsTitles();
96  
97          loadForm(root);
98  
99          watch((((DescribeClausePane) getPane(FIRST_CLAUSE))));
100         addWatches();
101     }
102 
103     /**
104      * Nacte formular.
105      *
106      * @param root rodicovsky element
107      * @throws LoadException
108      */
109     private void loadForm(Object root) throws LoadException {
110         if (root != null) {
111             if (root instanceof Element) {
112                 // Načtení uloženého dotazu
113                 Element rootNode = (Element) root;
114                 loadElement(rootNode, (((DescribeClausePane) getPane(FIRST_CLAUSE))));
115                 loadQueryPartsElements((Element) root, queryFormParts);
116 
117             } else if (root instanceof ParseTree) {
118                 setVariables((ParseTree) root);
119             }
120         }
121     }
122 
123     /**
124      * Inicializace pole casti.
125      */
126     private void initializeQueryFormParts() {
127         queryFormParts = new ArrayList<>();
128 
129         queryFormParts.add(new DescribeClausePane(this));
130 
131         queryFormParts.add(new FromClausePane(this));
132         queryFormParts.add(new WhereClausePane(this));
133         queryFormParts.add(new OrderByClausePane(this));
134         queryFormParts.add(new GroupByClausePane(this));
135         queryFormParts.add(new HavingClausePane(this));
136         queryFormParts.add(new LimitOffsetClausePane());
137         queryFormParts.add(new ValuesClausePane(this));
138     }
139 
140     /**
141      * Nastavi kolektory promennych.
142      */
143     private void addVariablesCollectors() {
144         ((DescribeClausePane) getPane(FIRST_CLAUSE)).addVariablesCollector(
145                 createCollector(describeClauseVariables, whereClauseVariables, groupByClauseVariables,
146                         orderByClauseVariables, valuesClauseVariables));
147 
148         ((WhereClausePane) getPane(WHERE_CLAUSE)).addVariablesCollector(
149                 createCollector(whereClauseVariables, groupByClauseVariables, orderByClauseVariables,
150                         valuesClauseVariables));
151 
152         ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).addVariablesCollector(
153                 createCollector(orderByClauseVariables, whereClauseVariables, groupByClauseVariables,
154                         valuesClauseVariables));
155 
156         ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).addVariablesCollector(
157                 createCollector(groupByClauseVariables, whereClauseVariables, orderByClauseVariables,
158                         valuesClauseVariables));
159 
160         ((ValuesClausePane) getPane(VALUES_CLAUSE)).addVariablesCollector(
161                 createCollector(valuesClauseVariables, whereClauseVariables, groupByClauseVariables,
162                         orderByClauseVariables));
163     }
164 
165     /**
166      * Vrati panel ze seznamu casti formulare.
167      *
168      * @param paneType typ panelu
169      *
170      * @return panel ze seznamu casti formulare
171      */
172     private Object getPane(QUERY_PARTS paneType) {
173         return getPane(queryFormParts, paneType);
174     }
175 
176     /**
177      * Titulky panelu.
178      */
179     private void addPartsTitles() {
180         final ObservableList<Node> children = getChildren();
181         addChild(children, "DESCRIBE_QUERY_FRAGMENT", (DescribeClausePane) getPane(FIRST_CLAUSE));
182         addTitlesPanes(children);
183     }
184 
185     private void addTitlesPanes(ObservableList<Node> children) {
186         addChild(children, "FROM_QUERY_FRAGMENT", (FromClausePane) getPane(FROM_CLAUSE));
187         addChild(children, "WHERE_QUERY_FRAGMENT", (WhereClausePane) getPane(WHERE_CLAUSE));
188         addChild(children, "GROUP_BY_QUERY_FRAGMENT", (GroupByClausePane) getPane(GROUP_BY_CLAUSE));
189         addChild(children, "HAVING_QUERY_FRAGMENT", (HavingClausePane) getPane(HAVING_CLAUSE));
190         addChild(children, "ORDER_BY_QUERY_FRAGMENT", (OrderByClausePane) getPane(ORDER_BY_CLAUSE));
191         addChild(children, "MODIFIERS_QUERY_FRAGMENT", (LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE));
192         addChild(children, "VALUES_QUERY_FRAGMENT", (ValuesClausePane) getPane(VALUES_CLAUSE));
193     }
194 
195     /**
196      * Vlozi {@code CustomTitledPane} do seznamu uzlu.
197      *
198      * @param children seznam uzlu
199      * @param title titulek
200      * @param content obsah (panel)
201      */
202     private void addChild(ObservableList<Node> children, final String title, final Node... content) {
203         children.add(new CustomTitledPane(Messages.getString(title), content));
204     }
205 
206     /**
207      * Nastavení hlídání změn.
208      */
209     private void addWatches() {
210         watch((FromClausePane) getPane(FROM_CLAUSE));
211         watch((WhereClausePane) getPane(WHERE_CLAUSE));
212         watch(((OrderByClausePane) getPane(ORDER_BY_CLAUSE)));
213         watch(((GroupByClausePane) getPane(GROUP_BY_CLAUSE)));
214         watch(((HavingClausePane) getPane(HAVING_CLAUSE)));
215         watch(((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)));
216         watch(((ValuesClausePane) getPane(VALUES_CLAUSE)));
217     }
218 
219     @Override
220     protected void setVariables(ParseTree root) throws LoadException {
221         boolean varsLoaded = false; //auxiliary variable helps to loading DESCRIBE variables
222         Stack<SparqlParserNode> nodeStack = new Stack<>(); //current path in parse tree
223         nodeStack.push(new SparqlParserNode(root));
224         while (!nodeStack.isEmpty()) {
225             SparqlParserNode currentNode = nodeStack.pop();
226             ParseTree nodeData = currentNode.getNodeData();
227             if (nodeData instanceof SparqlParser.DescribeQueryContext) { //part with variables of query
228                 nodeStack.push(currentNode);
229                 if (!varsLoaded) {
230                     ((DescribeClausePane) getPane(FIRST_CLAUSE)).load(nodeData);
231                     varsLoaded = true;
232                 } else {
233                     getTreeChild(currentNode, nodeStack);
234                 }
235             } else if (nodeData instanceof SparqlParser.DatasetClauseContext) { //from clause
236                 ((FromClausePane) getPane(FROM_CLAUSE)).load(nodeData);
237 
238             } else if (nodeData instanceof SparqlParser.LimitClauseContext) { //limit clause
239                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).load(nodeData);
240 
241             } else if (nodeData instanceof SparqlParser.OffsetClauseContext) { //offset clause
242                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).load(nodeData);
243 
244             } else if (nodeData instanceof SparqlParser.OrderConditionContext) { //order clause
245                 ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).load(nodeData);
246 
247             } else if (nodeData instanceof SparqlParser.HavingConditionContext) { //order clause
248                 ((HavingClausePane) getPane(HAVING_CLAUSE)).load(nodeData);
249 
250             } else if (nodeData instanceof SparqlParser.GroupConditionContext) { //group by clause
251                 ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).load(nodeData);
252 
253             } else if (nodeData instanceof SparqlParser.WhereClauseContext) { //where clause
254                 new SparqlParserWhereClauseWalker(nodeData, ((WhereClausePane) getPane(WHERE_CLAUSE)))
255                         .processWhereClauseDFS();
256 
257             } else if (nodeData instanceof SparqlParser.ValuesClauseContext) { // Values clause
258                 ((ValuesClausePane) getPane(VALUES_CLAUSE)).load(nodeData);
259 
260             } else { //uninsteresting node -> get next node
261                 nodeStack.push(currentNode);
262                 getTreeChild(currentNode, nodeStack);
263             }
264         }
265     }
266 
267     /**
268      * Pokusí se vložit proměnnou do klauzule DESCRIBE. Proměnná nebude vložena,
269      * pokud nemá platný název nebo je již v klauzuli obsažena.
270      *
271      * @param variableName Název proměnné.
272      */
273     public final void tryAddVariableToDescribeClause(final String variableName) {
274         if (SparqlValidationUtils.isVariableNameValid(variableName)
275                 && !describeClauseVariables.contains(variableName)) {
276             ((DescribeClausePane) getPane(FIRST_CLAUSE)).addVariable(variableName);
277         }
278     }
279 
280     @Override
281     public final ObservableList<String> getSortedVariables() {
282         ObservableSet<String> variables = FXCollections.observableSet();
283         variables.addAll(this.getNetVariables());
284         ((WhereClausePane) getPane(WHERE_CLAUSE)).getSubSelectPanes().forEach((subSelectPane) -> variables.addAll(subSelectPane.getSubSelectQueryPane().getSelectedVariables()));
285         return FXCollections.observableArrayList(variables).sorted(String.CASE_INSENSITIVE_ORDER);
286     }
287 
288     @Override
289     public final String getQueryPart() {
290         return ((DescribeClausePane) getPane(FIRST_CLAUSE)).getQueryPart()
291                 + ((FromClausePane) getPane(FROM_CLAUSE)).getQueryPart()
292                 + "WHERE " //$NON-NLS-1$
293                 + ((WhereClausePane) getPane(WHERE_CLAUSE)).getQueryPart()
294                 + ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).getQueryPart()
295                 + ((HavingClausePane) getPane(HAVING_CLAUSE)).getQueryPart()
296                 + ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).getQueryPart()
297                 + ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)).getQueryPart()
298                 + ((ValuesClausePane) getPane(VALUES_CLAUSE)).getQueryPart() + " "; //$NON-NLS-1$
299     }
300 
301     @Override
302     public final List<SubSelectPane> getSubSelectPanes() {
303         return ((WhereClausePane) getPane(WHERE_CLAUSE)).getSubSelectPanes();
304     }
305 
306     @Override
307     public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
308         final Set<String> result = ((WhereClausePane) getPane(WHERE_CLAUSE)).getPrefixesUsed(appendDelimiter);
309         result.addAll(((DescribeClausePane) getPane(FIRST_CLAUSE)).getPrefixesUsed(appendDelimiter));
310         result.addAll(((FromClausePane) getPane(FROM_CLAUSE)).getPrefixesUsed(appendDelimiter));
311         result.addAll(((OrderByClausePane) getPane(ORDER_BY_CLAUSE)).getPrefixesUsed(appendDelimiter));
312         result.addAll(((GroupByClausePane) getPane(GROUP_BY_CLAUSE)).getPrefixesUsed(appendDelimiter));
313         result.addAll(((HavingClausePane) getPane(HAVING_CLAUSE)).getPrefixesUsed(appendDelimiter));
314         result.addAll(((ValuesClausePane) getPane(VALUES_CLAUSE)).getPrefixesUsed(appendDelimiter));
315         return result;
316     }
317 
318     @Override
319     public final void save(final Element root) {
320         Saveable.defaultSave(root, ((DescribeClausePane) getPane(FIRST_CLAUSE)),
321                 ((FromClausePane) getPane(FROM_CLAUSE)), ((WhereClausePane) getPane(WHERE_CLAUSE)),
322                 ((LimitOffsetClausePane) getPane(LIMIT_OFFSET_CLAUSE)),
323                 ((OrderByClausePane) getPane(ORDER_BY_CLAUSE)),
324                 ((GroupByClausePane) getPane(GROUP_BY_CLAUSE)),
325                 ((HavingClausePane) getPane(HAVING_CLAUSE)), ((ValuesClausePane) getPane(VALUES_CLAUSE)));
326     }
327 
328     @Override
329     protected final String getXMLQueryType() {
330         return XML_QUERY_TYPE_VALUE;
331     }
332 
333 }