View Javadoc
1   package de.tud.plt.r43ples.core;
2   
3   import de.tud.plt.r43ples.exception.InternalErrorException;
4   import de.tud.plt.r43ples.exception.QueryErrorException;
5   import de.tud.plt.r43ples.existentobjects.MergeCommit;
6   import de.tud.plt.r43ples.existentobjects.RevisionGraph;
7   import de.tud.plt.r43ples.management.Config;
8   import de.tud.plt.r43ples.management.R43plesRequest;
9   import de.tud.plt.r43ples.optimization.PathCalculationFabric;
10  import de.tud.plt.r43ples.optimization.PathCalculationInterface;
11  import de.tud.plt.r43ples.triplestoreInterface.TripleStoreInterfaceSingleton;
12  import org.apache.logging.log4j.LogManager;
13  import org.apache.logging.log4j.Logger;
14  
15  import java.util.regex.Matcher;
16  import java.util.regex.Pattern;
17  
18  /**
19   * Collection of information for creating a new merge commit.
20   *
21   * @author Stephan Hensel
22   */
23  public class MergeCommitDraft extends CommitDraft {
24  
25      /** The logger. **/
26      private Logger logger = LogManager.getLogger(MergeCommitDraft.class);
27  
28      /** The pattern modifier. **/
29      private final int patternModifier = Pattern.DOTALL + Pattern.MULTILINE + Pattern.CASE_INSENSITIVE;
30      /** The merge query pattern. **/
31      private final Pattern patternMergeQuery = Pattern.compile(
32              "(?<action>MERGE)\\s*(?<type>AUTO|MANUAL)?\\s*GRAPH\\s*<(?<graph>[^>]*?)>\\s*BRANCH\\s*\"(?<branchNameFrom>[^\"]*?)\"\\s*INTO\\s*BRANCH\\s*\"(?<branchNameInto>[^\"]*?)\"(?<with>\\s*WITH\\s*\\{(?<triples>.*)\\})?",
33              patternModifier);
34  
35      /** The triples of the query WITH part. **/
36      private String triples;
37      /** The branch name (from). **/
38      private String branchNameFrom;
39      /** The branch name (into). **/
40      private String branchNameInto;
41      /** The graph name **/
42      private String graphName;
43      /** The revision graph. **/
44      private RevisionGraph revisionGraph;
45      /** The query type (FORCE, AUTO, MANUAL). **/
46      private MergeTypes type;
47      /** The query action (MERGE, REBASE, MERGE FF). **/
48      private MergeActions action;
49      /** States if the WITH part is available. **/
50      private boolean with;
51  
52      /** States if this commit draft was created by a request or add and delete sets. (true => request, false => add/delete sets) **/
53      private boolean isCreatedWithRequest;
54  
55      //Dependencies
56      /** The path calculation interface to use. **/
57      private PathCalculationInterface pathCalculationInterface;
58  
59  
60      /**
61       * The constructor.
62       *
63       * @param request the request received by R43ples
64       * @throws InternalErrorException
65       */
66      public MergeCommitDraft(R43plesRequest request) throws InternalErrorException {
67          super(request);
68  
69          this.extractRequestInformation();
70          this.pathCalculationInterface = PathCalculationFabric.getInstance(this.revisionGraph);
71          this.isCreatedWithRequest = true;
72      }
73  
74      /**
75       * The constructor.
76       * Creates an merge commit draft by using the corresponding meta information.
77       *
78       * @param graphName the graph name
79       * @param branchNameFrom the branch name (from)
80       * @param branchNameInto the branch name (into)
81       * @param user the user
82       * @param message the message
83       * @param action the query action (MERGE, REBASE, MERGE FF)
84       * @param triples the triples of the query WITH part
85       * @param type the query type (FORCE, AUTO, MANUAL)
86       * @param with states if the WITH part is available
87       * @throws InternalErrorException
88       */
89      protected MergeCommitDraft(String graphName, String branchNameFrom, String branchNameInto, String user, String message, MergeActions action, String triples, MergeTypes type, boolean with) throws InternalErrorException {
90          super(null);
91  
92          this.setUser(user);
93          this.setMessage(message);
94  
95          this.graphName = graphName;
96          this.revisionGraph = new RevisionGraph(graphName);
97          this.branchNameFrom = branchNameFrom;
98          this.branchNameInto = branchNameInto;
99          this.action = action;
100         this.triples = triples;
101         this.type = type;
102         this.with = with;
103         this.pathCalculationInterface = PathCalculationFabric.getInstance(this.revisionGraph);
104 
105         this.isCreatedWithRequest = false;
106     }
107 
108     /**
109      * Extracts the request information and stores it to local variables.
110      *
111      * @throws InternalErrorException
112      */
113     private void extractRequestInformation() throws InternalErrorException {
114         Matcher m = patternMergeQuery.matcher(getRequest().query_sparql);
115 
116         boolean foundEntry = false;
117 
118         while (m.find()) {
119             foundEntry = true;
120 
121             switch (m.group("action").toUpperCase()) {
122                 case "MERGE":
123                     action = MergeActions.MERGE;
124                     break;
125                 default:
126                     action = null;
127                     break;
128             }
129             String typeID = m.group("type");
130             if (typeID != null) {
131                 switch (typeID.toUpperCase()) {
132                     case "AUTO":
133                         type = MergeTypes.AUTO;
134                         break;
135                     case "MANUAL":
136                         type = MergeTypes.MANUAL;
137                         break;
138                     default:
139                         type = null;
140                         break;
141                 }
142             } else {
143                 type = null;
144             }
145 
146             graphName = m.group("graph");
147             revisionGraph = new RevisionGraph(graphName);
148             branchNameFrom = m.group("branchNameFrom");
149             branchNameInto = m.group("branchNameInto");
150             with = m.group("with") != null;
151             triples = m.group("triples");
152 
153             logger.debug("type: " + type);
154             logger.debug("graph: " + graphName);
155             logger.debug("branchNameFrom: " + branchNameFrom);
156             logger.debug("branchNameInto: " + branchNameInto);
157             logger.debug("with: " + with);
158             logger.debug("triples: " + triples);
159         }
160         if (!foundEntry) {
161             throw new QueryErrorException("Error in query: " + getRequest().query_sparql);
162         }
163     }
164 
165     /**
166      * Creates the commit draft as a new commit in the triple store and creates the corresponding revisions.
167      *
168      * @return the created commit
169      */
170     protected MergeCommit createCommitInTripleStore() throws InternalErrorException {
171         // Select the right child element and create a corresponding commit using the createCommitInTripleStore method.
172         if (action.equals(MergeActions.MERGE)) {
173             String revisionGraphURI = getRevisionGraph().getRevisionGraphUri();
174             String revisionUriFrom = getRevisionGraph().getRevisionUri(getBranchNameFrom());
175             String revisionUriInto = getRevisionGraph().getRevisionUri(getBranchNameInto());
176 
177             // Check the named graph existence
178             if (!getUriCalculator().checkNamedGraphExistence(getGraphName())) {
179                 logger.warn("Graph <" + getGraphName() + "> does not exist.");
180                 throw new InternalErrorException("Graph <" + getGraphName() + "> does not exist.");
181             }
182 
183             // Check if from and into are different revisions
184             if (revisionUriFrom.equals(revisionUriInto)) {
185                 // Branches are equal - throw error
186                 throw new InternalErrorException("Specified branches are equal");
187             }
188 
189             // Check if both are terminal nodes
190             if (!(getRevisionGraph().hasBranch(getBranchNameFrom()) && getRevisionGraph().hasBranch(getBranchNameInto()))) {
191                 throw new InternalErrorException("No terminal nodes were used");
192             }
193 
194             // Check if the into revision is derived from the from revision and fast forward can be applied
195             String query = Config.prefixes
196                     + String.format("ASK { GRAPH <%s> { "
197                             + "<%s> rmo:wasDerivedFrom+ <%s> ."
198                             + " }} ",
199                     revisionGraphURI, revisionUriFrom, revisionUriInto);
200             if (!getTripleStoreInterface().executeAskQuery(query)) {
201                 ThreeWayMergeCommitDraft threeWayMergeCommit = new ThreeWayMergeCommitDraft(graphName, branchNameFrom, branchNameInto, getUser(), getMessage(), triples, type, with);
202                 return threeWayMergeCommit.createCommitInTripleStore();
203             } else {
204                 FastForwardMergeCommitDraft fastForwardMergeCommitDraft = new FastForwardMergeCommitDraft(graphName, branchNameFrom, branchNameInto, getUser(), getMessage(), triples, type, with);
205                 return fastForwardMergeCommitDraft.createCommitInTripleStore();
206             }
207         } else {
208             throw new QueryErrorException("Error in query: " + getRequest().query_sparql);
209         }
210     }
211 
212     /**
213      * Get the triples of the query WITH part.
214      *
215      * @return the triples of the query WITH part
216      */
217     protected String getTriples() {
218         return triples;
219     }
220 
221     /**
222      * Get the branch name (from).
223      *
224      * @return the branch name
225      */
226     protected String getBranchNameFrom() {
227         return branchNameFrom;
228     }
229 
230     /**
231      * Get the branch name (into).
232      *
233      * @return the branch name
234      */
235     protected String getBranchNameInto() {
236         return branchNameInto;
237     }
238 
239     /**
240      * The revision graph.
241      *
242      * @return the revision graph
243      */
244     protected RevisionGraph getRevisionGraph() {
245         return revisionGraph;
246     }
247 
248     /**
249      * The graph name.
250      *
251      * @return the graph name
252      */
253     protected String getGraphName() {
254         return graphName;
255     }
256 
257     /**
258      * Get the query type (FORCE, AUTO, MANUAL).
259      *
260      * @return the query type
261      */
262     protected MergeTypes getType() {
263         return type;
264     }
265 
266     /**
267      * Get the query action (MERGE, REBASE, MERGE FF).
268      *
269      * @return the query action
270      */
271     protected MergeActions getAction() {
272         return action;
273     }
274 
275     /**
276      * Get the boolean indicator if the WITH part os available.
277      *
278      * @return true if the WITH part is available
279      */
280     protected boolean isWith() {
281         return with;
282     }
283 
284     /**
285      * Get the path calculation interface.
286      *
287      * @return the path calculation interface
288      */
289     protected PathCalculationInterface getPathCalculationInterface() {
290         return pathCalculationInterface;
291     }
292 
293     /**
294      * Copy a full graph from one branch to another.
295      * @param sourceGraphURI the URI of the source graph
296      * @param targetGraphURI the URI of the target graph
297      * */
298     protected void fullGraphCopy(String sourceGraphURI, String targetGraphURI) {
299         getTripleStoreInterface().executeUpdateQuery(
300                 "COPY GRAPH <" + sourceGraphURI + "> TO GRAPH <"+ targetGraphURI + ">");
301     }
302 
303 }