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.delete;
21  
22  import cz.zcu.mre.sparkle.Messages;
23  import cz.zcu.mre.sparkle.data.*;
24  import cz.zcu.mre.sparkle.gui.mainForm.MainForm;
25  import cz.zcu.mre.sparkle.gui.query.CustomTitledPane;
26  import cz.zcu.mre.sparkle.gui.query.QueryFormPane;
27  import cz.zcu.mre.sparkle.gui.query.modifiers.GroupGraphPatternPane;
28  import cz.zcu.mre.sparkle.gui.query.modifiers.UsingClausePane;
29  import cz.zcu.mre.sparkle.gui.query.queryMainParts.WhereClausePane;
30  import cz.zcu.mre.sparkle.gui.query.queryMainParts.WithClausePane;
31  import cz.zcu.mre.sparkle.gui.query.queryTypes.subselect.SubSelectPane;
32  import cz.zcu.mre.sparkle.tools.*;
33  import cz.zcu.mre.sparkle.tools.SparqlParser;
34  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserNode;
35  import cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserWhereClauseWalker;
36  import javafx.collections.FXCollections;
37  import javafx.collections.ObservableList;
38  import javafx.collections.ObservableSet;
39  import javafx.scene.Node;
40  import org.antlr.v4.runtime.tree.ParseTree;
41  import org.w3c.dom.Element;
42  import javax.xml.parsers.ParserConfigurationException;
43  import javax.xml.transform.TransformerException;
44  import java.util.List;
45  import java.util.Set;
46  import java.util.Stack;
47  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.getTreeChild;
48  import static cz.zcu.mre.sparkle.tools.sparqlParser.SparqlParserUtils.searchNode;
49  
50  /**
51   * The panel controller for a DELETE/INSERT query.
52   *
53   * @author Josef Kazak
54   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
55   */
56  public class DeleteInsertQueryFormPane
57          extends QueryFormPane<Boolean> {
58  
59      public static final String XML_QUERY_TYPE_VALUE = "deleteInsert"; //$NON-NLS-1$
60  
61      private WithClausePane withClausePane;
62      private GroupGraphPatternPane deleteClausePane;
63      private UsingClausePane usingClausePane;
64      private GroupGraphPatternPane insertClausePane;
65      private GroupGraphPatternPane whereClausePane;
66      private ObservableSet<String> deleteClauseVariables;
67      private ObservableSet<String> insertClauseVariables;
68      private ObservableSet<String> whereClauseVariables;
69  
70      public DeleteInsertQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
71              String paneType) {
72          super(mainForm, dataAgent, localStorage, paneType);
73      }
74  
75      public DeleteInsertQueryFormPane(final MainForm mainForm, final DataAgent dataAgent, final Storage localStorage,
76              final Object root, String paneType) throws ParserConfigurationException, TransformerException, Saveable.LoadException {
77          super(mainForm, dataAgent, localStorage, root, paneType);
78      }
79  
80      @Override
81      public final void load(final Object root) throws Saveable.LoadException {
82          deleteClauseVariables = FXCollections.observableSet();
83          insertClauseVariables = FXCollections.observableSet();
84          whereClauseVariables = FXCollections.observableSet();
85  
86          initializeQueryFormParts();
87          addVariablesCollectors();
88          addPartsTitles();
89          loadForm(root);
90          addWatches();
91      }
92  
93      private void addWatches() {
94          watch(withClausePane);
95          watch(insertClausePane);
96          watch(deleteClausePane);
97          watch(usingClausePane);
98          watch(whereClausePane);
99      }
100 
101     private void loadForm(Object root) throws LoadException {
102         if (root != null) {
103             if (root instanceof Element) {
104                 // Load a saved query
105                 Element rootNode = (Element) root;
106                 loadElement(rootNode, withClausePane);
107                 loadElement(rootNode, deleteClausePane);
108                 loadElement(rootNode, insertClausePane);
109                 loadElement(rootNode, usingClausePane);
110                 loadElement(rootNode, whereClausePane);
111             } else if (root instanceof ParseTree) {
112                 setVariables((ParseTree) root);
113             }
114         }
115     }
116 
117     private void addPartsTitles() {
118         final ObservableList<Node> children = getChildren();
119 
120         children.add(new CustomTitledPane(Messages.getString("WITH_QUERY_FRAGMENT"), withClausePane)); //$NON-NLS-1$
121         children.add(new CustomTitledPane(Messages.getString("DELETE_INSERT_QUERY_FRAGMENT_DELETE"),
122                 deleteClausePane)); //$NON-NLS-1$
123         children.add(new CustomTitledPane(Messages.getString("DELETE_INSERT_QUERY_FRAGMENT_INSERT"),
124                 insertClausePane)); //$NON-NLS-1$
125         children.add(new CustomTitledPane(Messages.getString("USING_QUERY_FRAGMENT"), usingClausePane)); //$NON-NLS-1$
126         children.add(new CustomTitledPane(Messages.getString("WHERE_QUERY_FRAGMENT"), whereClausePane)); //$NON-NLS-1$
127     }
128 
129     private void addVariablesCollectors() {
130         deleteClausePane.addVariablesCollector(
131                 createCollector(deleteClauseVariables, insertClauseVariables, whereClauseVariables));
132         insertClausePane = new DeleteInsertInsertClausePane(this);
133         insertClausePane.addVariablesCollector(
134                 createCollector(deleteClauseVariables, insertClauseVariables, whereClauseVariables));
135         whereClausePane.addVariablesCollector(
136                 createCollector(deleteClauseVariables, insertClauseVariables, whereClauseVariables));
137     }
138 
139     private void initializeQueryFormParts() {
140         withClausePane = new WithClausePane(this);
141         deleteClausePane = new DeleteInsertDeleteClausePane(this);
142         usingClausePane = new UsingClausePane(this);
143         whereClausePane = new WhereClausePane(this);
144     }
145 
146     @SuppressWarnings("ConstantConditions")
147     @Override
148     protected void setVariables(ParseTree root) throws Saveable.LoadException {
149         Stack<SparqlParserNode> nodeStack = new Stack<>(); //current path in parse tree
150         nodeStack.push(new SparqlParserNode(root));
151 
152         while (!nodeStack.isEmpty()) {
153             SparqlParserNode currentNode = nodeStack.pop();
154             ParseTree nodeData = currentNode.getNodeData();
155 
156             if (nodeData instanceof SparqlParser.ModifyContext
157                     || nodeData instanceof SparqlParser.DeleteWhereContext) {
158                 int childrenCount = nodeData.getChildCount();
159 
160                 for (int i = 0; i < childrenCount; i++) {
161                     ParseTree childNode = nodeData.getChild(i);
162                     if (childNode instanceof SparqlParser.IriContext
163                             && ((SparqlParser.ModifyContext) nodeData).WITH() != null) { //using clause
164                         withClausePane.load(childNode);
165 
166                     } else if (childNode instanceof SparqlParser.DeleteClauseContext) { //DELETE clause
167                         new SparqlParserWhereClauseWalker(searchNode(childNode, SparqlParser.QuadPatternContext.class),
168                                 deleteClausePane).processWhereClauseDFS();
169 
170                     } else if (childNode instanceof SparqlParser.InsertClauseContext) { //INSERT clause
171                         new SparqlParserWhereClauseWalker(searchNode(childNode, SparqlParser.QuadPatternContext.class),
172                                 insertClausePane).processWhereClauseDFS();
173 
174                     } else if (childNode instanceof SparqlParser.UsingClauseContext) { //USING clause
175                         usingClausePane.load(childNode);
176 
177                     } else if (childNode instanceof SparqlParser.GroupGraphPatternContext) { //WHERE clause
178                         new SparqlParserWhereClauseWalker(
179                                 searchNode(childNode, SparqlParser.GroupGraphPatternSubContext.class), whereClausePane)
180                                 .processWhereClauseDFS();
181 
182                     } else if (childNode instanceof SparqlParser.QuadPatternContext) { //DELETE WHERE
183                         new SparqlParserWhereClauseWalker(childNode, deleteClausePane).processWhereClauseDFS();
184                     }
185                 }
186                 break;
187             } else { //uninsteresting node -> get next node
188                 nodeStack.push(currentNode);
189                 getTreeChild(currentNode, nodeStack);
190             }
191         }
192     }
193 
194     @Override
195     public final ObservableList<String> getSortedVariables() {
196         ObservableSet<String> variables = FXCollections.observableSet();
197         variables.addAll(this.getNetVariables());
198 
199         whereClausePane.getSubSelectPanes().forEach((subSelectPane) -> variables.addAll(subSelectPane.getSubSelectQueryPane().getSelectedVariables()));
200 
201         return FXCollections.observableArrayList(variables).sorted(String.CASE_INSENSITIVE_ORDER);
202     }
203 
204     @Override
205     public final String getQueryPart() {
206         final StringBuilder sb = new StringBuilder();
207         addQueryPart(sb, "WITH ", withClausePane.getQueryPart()); //$NON-NLS-1$
208 
209         final int queryLength = sb.length();
210 
211         addQueryPart(sb, "INSERT ", insertClausePane.getQueryPart()); //$NON-NLS-1$
212         addQueryPart(sb, Definitions.EMPTY_STRING, usingClausePane.getQueryPart());
213         addQueryPart(sb, "WHERE ", whereClausePane.getQueryPart()); //$NON-NLS-1$
214 
215         String deleteClauseQueryPart = deleteClausePane.getQueryPart();
216         if (!deleteClauseQueryPart.isEmpty()) {
217             if (sb.length() > 0) {
218                 sb.insert(queryLength, deleteClauseQueryPart).insert(queryLength, "DELETE "); //$NON-NLS-1$
219             } else {
220                 sb.append("DELETE WHERE ").append(deleteClauseQueryPart); //$NON-NLS-1$
221             }
222         }
223 
224         return sb.toString();
225     }
226 
227     private void addQueryPart(StringBuilder sb, String prefix, String suffix) {
228         if (!suffix.isEmpty()) {
229             sb.append(prefix).append(suffix);
230         }
231     }
232 
233     @Override
234     public final List<SubSelectPane> getSubSelectPanes() {
235         return whereClausePane.getSubSelectPanes();
236     }
237 
238     @Override
239     public final Set<String> getPrefixesUsed(final boolean appendDelimiter) {
240         final Set<String> result = whereClausePane.getPrefixesUsed(appendDelimiter);
241         result.addAll(deleteClausePane.getPrefixesUsed(appendDelimiter));
242         result.addAll(insertClausePane.getPrefixesUsed(appendDelimiter));
243         result.addAll(usingClausePane.getPrefixesUsed(appendDelimiter));
244         result.addAll(withClausePane.getPrefixesUsed(appendDelimiter));
245         return result;
246     }
247 
248     @Override
249     public final void save(final Element root) {
250         Saveable.defaultSave(root, withClausePane, deleteClausePane, insertClausePane, usingClausePane,
251                 whereClausePane);
252     }
253 
254     @Override
255     protected final String getXMLQueryType() {
256         return XML_QUERY_TYPE_VALUE;
257     }
258 
259 }