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.*;
6   import de.tud.plt.r43ples.management.Config;
7   import de.tud.plt.r43ples.management.R43plesRequest;
8   import de.tud.plt.r43ples.iohelper.Helper;
9   import de.tud.plt.r43ples.optimization.PathCalculationFabric;
10  import de.tud.plt.r43ples.optimization.PathCalculationInterface;
11  import org.apache.logging.log4j.LogManager;
12  import org.apache.logging.log4j.Logger;
13  
14  import java.util.ArrayList;
15  import java.util.Iterator;
16  import java.util.regex.Matcher;
17  import java.util.regex.Pattern;
18  
19  /**
20   * Collection of information for creating a new pick commit.
21   *
22   * @author Stephan Hensel
23   */
24  public class PickCommitDraft extends CommitDraft {
25  
26      /** The logger. **/
27      private Logger logger = LogManager.getLogger(PickCommitDraft.class);
28  
29      /** The pattern modifier. **/
30      private final int patternModifier = Pattern.DOTALL + Pattern.MULTILINE + Pattern.CASE_INSENSITIVE;
31      /** The merge query pattern. **/
32      private final Pattern patternPickQuery = Pattern.compile(
33              "PICK\\s*GRAPH\\s*<(?<graph>[^>]*?)>\\s*REVISION\\s*\"(?<startRevisionIdentifier>[^\"]*?)\"\\s*(TO\\s*REVISION\\s*\"(?<endRevisionIdentifier>[^\"]*?)\"\\s*)?INTO\\s*BRANCH\\s*\"(?<targetBranchIdentifier>[^\"]*?)\"\"",
34              patternModifier);
35  
36      /** The start revision identifier. **/
37      private String startRevisionIdentifier;
38      /** The end revision identifier. **/
39      private String endRevisionIdentifier;
40      /** The target branch identifier (into). **/
41      private String targetBranchIdentifier;
42      /** The graph name **/
43      private String graphName;
44      /** The revision graph. **/
45      private RevisionGraph revisionGraph;
46  
47      /** States if this commit draft was created by a request or add and delete sets. (true => request, false => add/delete sets) **/
48      private boolean isCreatedWithRequest;
49  
50      //Dependencies
51      /** The path calculation interface to use. **/
52      private PathCalculationInterface pathCalculationInterface;
53  
54  
55      /**
56       * The constructor.
57       *
58       * @param request the request received by R43ples
59       * @throws InternalErrorException
60       */
61      public PickCommitDraft(R43plesRequest request) throws InternalErrorException {
62          super(request);
63  
64          this.extractRequestInformation();
65          this.isCreatedWithRequest = true;
66          this.pathCalculationInterface = PathCalculationFabric.getInstance(this.revisionGraph);
67      }
68  
69      /**
70       * The constructor.
71       * Creates a pick commit draft by using the corresponding meta information.
72       *
73       * @param graphName the graph name
74       * @param startRevisionIdentifier the start revision identifier
75       * @param endRevisionIdentifier the end revision identifier
76       * @param targetBranchIdentifier the target branch identifier
77       * @param user the user
78       * @param message the message
79       * @throws InternalErrorException
80       */
81      protected PickCommitDraft(String graphName, String startRevisionIdentifier, String endRevisionIdentifier, String targetBranchIdentifier, String user, String message) throws InternalErrorException {
82          super(null);
83  
84          this.setUser(user);
85          this.setMessage(message);
86  
87          this.graphName = graphName;
88          this.revisionGraph = new RevisionGraph(graphName);
89          this.startRevisionIdentifier = startRevisionIdentifier;
90          this.endRevisionIdentifier = endRevisionIdentifier;
91          this.targetBranchIdentifier = targetBranchIdentifier;
92          this.pathCalculationInterface = PathCalculationFabric.getInstance(this.revisionGraph);
93  
94          this.isCreatedWithRequest = false;
95      }
96  
97      /**
98       * Extracts the request information and stores it to local variables.
99       *
100      * @throws InternalErrorException
101      */
102     private void extractRequestInformation() throws InternalErrorException {
103         Matcher m = patternPickQuery.matcher(getRequest().query_sparql);
104 
105         boolean foundEntry = false;
106 
107         while (m.find()) {
108             foundEntry = true;
109 
110             graphName = m.group("graph");
111             revisionGraph = new RevisionGraph(graphName);
112 
113             startRevisionIdentifier = m.group("startRevisionIdentifier");
114             endRevisionIdentifier = m.group("endRevisionIdentifier");
115             targetBranchIdentifier = m.group("targetBranchIdentifier");
116 
117             logger.debug("graph: " + graphName);
118             logger.debug("startRevisionIdentifier: " + startRevisionIdentifier);
119             logger.debug("endRevisionIdentifier: " + endRevisionIdentifier);
120             logger.debug("targetBranchIdentifier: " + targetBranchIdentifier);
121         }
122         if (!foundEntry) {
123             throw new QueryErrorException("Error in query: " + getRequest().query_sparql);
124         }
125     }
126 
127     /**
128      * Tries to create a new commit draft as a new commit in the triple store.
129      * If possible it will create the corresponding revision and the meta data.
130      *
131      * @return the commit (has attribute which indicates if the commit was executed or not)
132      * @throws InternalErrorException
133      */
134     protected PickCommit createCommitInTripleStore() throws InternalErrorException {
135 
136         if (!getUriCalculator().checkNamedGraphExistence(graphName)) {
137             logger.warn("Graph <" + graphName + "> does not exist.");
138             throw new InternalErrorException("Graph <" + graphName + "> does not exist.");
139         }
140 
141         // Check if it is a valid target branch identifier
142         if (!(revisionGraph.hasBranch(targetBranchIdentifier))) {
143             throw new InternalErrorException("No terminal nodes were used");
144         }
145 
146         ArrayList<Revision> usedSourceRevisions = new ArrayList<>();
147         ArrayList<Revision> generatedRevisions = new ArrayList<>();
148 
149         Branch usedTargetBranch = revisionGraph.getBranch(targetBranchIdentifier, true);
150         Revision usedTargetRevision = new Revision(revisionGraph, revisionGraph.getRevisionUri(targetBranchIdentifier), false);
151         Path path = null;
152         Revision startRevision = new Revision(revisionGraph, startRevisionIdentifier, true);
153         Revision endRevision;
154         if (endRevisionIdentifier != null) {
155             endRevision = new Revision(revisionGraph, endRevisionIdentifier, true);
156             path = pathCalculationInterface.getPathBetweenStartAndTargetRevision(endRevision, startRevision);
157         }
158 
159         String commitURI = getUriCalculator().getNewPickCommitURI(revisionGraph, startRevisionIdentifier, endRevisionIdentifier, targetBranchIdentifier, usedTargetRevision.getRevisionIdentifier());
160 
161         // Copy revisions
162         Revision generatedRevision = null;
163         if ((path == null) || (path.getRevisionPath().size() == 1)) {
164             generatedRevision = copyRevisionToTargetBranch(startRevision, usedTargetBranch, commitURI);
165             usedSourceRevisions.add(startRevision);
166             generatedRevisions.add(generatedRevision);
167 
168             // Move source branch to new revision
169             moveBranchReference(revisionGraph.getRevisionGraphUri(), usedTargetBranch.getReferenceURI(), usedTargetRevision.getRevisionURI(), generatedRevision.getRevisionURI());
170 
171             // Update the target branch object
172             usedTargetBranch = revisionGraph.getBranch(targetBranchIdentifier, true);
173         } else {
174             Iterator<Revision> iteRev = path.getRevisionPath().iterator();
175             while(iteRev.hasNext()) {
176                 Revision currentRevision = iteRev.next();
177                 generatedRevision = copyRevisionToTargetBranch(currentRevision, usedTargetBranch, commitURI);
178                 usedSourceRevisions.add(currentRevision);
179                 generatedRevisions.add(generatedRevision);
180 
181                 // Move source branch to new revision
182                 moveBranchReference(revisionGraph.getRevisionGraphUri(), usedTargetBranch.getReferenceURI(), usedTargetRevision.getRevisionURI(), generatedRevision.getRevisionURI());
183 
184                 // Update the target branch object
185                 usedTargetBranch = revisionGraph.getBranch(targetBranchIdentifier, true);
186             }
187         }
188 
189         return addMetaInformation(usedTargetRevision, usedTargetBranch, commitURI, usedSourceRevisions, generatedRevisions);
190     }
191 
192     /**
193      * Adds meta information for the commit to the revision graph.
194      *
195      * <img src="{@docRoot}../../doc/revision management description/r43ples-pick.png" />
196      *
197      * @param usedTargetRevision the used target revision (into)
198      * @param usedTargetBranch the used target branch (from)
199      * @param commitURI the commit URI
200      * @param usedSourceRevisions the used revisions
201      * @param generatedRevisions the generated revisions
202      * @return the created commit
203      * @throws InternalErrorException
204      */
205     private PickCommit addMetaInformation(Revision usedTargetRevision, Branch usedTargetBranch, String commitURI, ArrayList<Revision> usedSourceRevisions, ArrayList<Revision> generatedRevisions) throws InternalErrorException {
206 
207         String personUri = Helper.getUserURI(getUser());
208 
209         // Create a new commit (activity)
210         StringBuilder queryContent = new StringBuilder(1000);
211         queryContent.append(String.format(
212                 "<%s> a rmo:PickCommit, rmo:MergeCommit, rmo:Commit; %n"
213                         + "	rmo:wasAssociatedWith <%s> ; %n"
214                         + "	rmo:commitMessage \"%s\" ; %n"
215                         + "	rmo:timeStamp \"%s\"^^xsd:dateTime ; %n"
216                         + " rmo:usedTargetRevision <%s> ; %n"
217                         + " rmo:usedTargetBranch <%s> ; %n",
218                 commitURI, personUri, getMessage(), getTimeStamp(),
219                 usedTargetRevision.getRevisionURI(), usedTargetBranch.getReferenceURI()));
220 
221         String query = Config.prefixes
222                 + String.format("INSERT DATA { GRAPH <%s> { %s } }", revisionGraph.getRevisionGraphUri(),
223                 queryContent.toString());
224 
225         getTripleStoreInterface().executeUpdateQuery(query);
226 
227         return new PickCommit(revisionGraph, commitURI, getUser(), getTimeStamp(), getMessage(), usedSourceRevisions, usedTargetRevision, usedTargetBranch, generatedRevisions);
228     }
229 
230 
231     /**
232      * Copies a revision and adds meta information to the revision graph.
233      *
234      * @param revisionToCopy the original revision to copy
235      * @param targetBranch the target branch
236      * @param commitURI the associated commit URI
237      * @return the generated revision
238      */
239     private Revision copyRevisionToTargetBranch(Revision revisionToCopy, Branch targetBranch, String commitURI) throws InternalErrorException {
240 
241         String addSetContent = revisionToCopy.getChangeSet().getAddSetContent();
242         String deleteSetContent = revisionToCopy.getChangeSet().getDeleteSetContent();
243 
244         RevisionDraft revisionDraft = new RevisionDraft(getUriCalculator(), revisionGraph, targetBranch, addSetContent, deleteSetContent, false);
245         Revision generatedRevision = revisionDraft.createInTripleStore();
246 
247         // Create the corresponding meta data
248         StringBuilder queryContentInsert = new StringBuilder(1000);
249         queryContentInsert.append(String.format(
250                 "<%1$s> rmo:wasQuotedFrom <%2$s> . "
251                 + "<%3$s> prov:generated <%1$s> ; "
252                         + " rmo:hasChangeSet <%4$s> ;"
253                         + " rmo:usedSourceRevision <%2$s> .",
254                 generatedRevision.getRevisionURI(), revisionToCopy.getRevisionURI(), commitURI, generatedRevision.getChangeSet().getChangeSetURI()));
255 
256         String query = Config.prefixes	+ String.format(""
257                         + "INSERT DATA { GRAPH <%1$s> { %2$s } }",
258                 revisionGraph.getRevisionGraphUri(), queryContentInsert.toString());
259         getTripleStoreInterface().executeUpdateQuery(query);
260 
261         return generatedRevision;
262     }
263 
264 }