Skip to main content
summaryrefslogtreecommitdiffstats
blob: e3ba0fef2e0e6c0cd5cb07402920e866e50d153e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*******************************************************************************
 * Copyright (c) 2004, 2007 Boeing.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Boeing - initial API and implementation
 *******************************************************************************/
package org.eclipse.osee.orcs.db.internal.callable;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.eclipse.osee.database.schema.DatabaseTxCallable;
import org.eclipse.osee.framework.core.enums.BranchState;
import org.eclipse.osee.framework.core.enums.BranchType;
import org.eclipse.osee.framework.core.enums.ModificationType;
import org.eclipse.osee.framework.core.enums.StorageState;
import org.eclipse.osee.framework.core.enums.SystemUser;
import org.eclipse.osee.framework.core.enums.TransactionDetailsType;
import org.eclipse.osee.framework.core.enums.TxChange;
import org.eclipse.osee.framework.core.exception.OseeCoreException;
import org.eclipse.osee.framework.core.exception.OseeStateException;
import org.eclipse.osee.framework.core.model.Branch;
import org.eclipse.osee.framework.core.model.BranchFactory;
import org.eclipse.osee.framework.core.model.MergeBranch;
import org.eclipse.osee.framework.core.model.TransactionRecord;
import org.eclipse.osee.framework.core.model.TransactionRecordFactory;
import org.eclipse.osee.framework.core.model.cache.BranchCache;
import org.eclipse.osee.framework.core.model.cache.TransactionCache;
import org.eclipse.osee.framework.database.IOseeDatabaseService;
import org.eclipse.osee.framework.database.core.IOseeStatement;
import org.eclipse.osee.framework.database.core.OseeConnection;
import org.eclipse.osee.framework.jdk.core.util.GUID;
import org.eclipse.osee.framework.jdk.core.util.time.GlobalTime;
import org.eclipse.osee.logger.Log;
import org.eclipse.osee.orcs.db.internal.branch.CreateDatabaseBranch;

/**
 * @author Roberto E. Escobar
 */
public class CreateBranchDatabaseTxCallable extends DatabaseTxCallable<Branch> {

   private static final String INSERT_TX_DETAILS =
      "INSERT INTO osee_tx_details (branch_id, transaction_id, osee_comment, time, author, tx_type) VALUES (?,?,?,?,?,?)";

   // descending order is used so that the most recent entry will be used if there are multiple rows with the same gamma (an error case)
   private static final String SELECT_ADDRESSING =
      "SELECT gamma_id, mod_type FROM osee_txs txs WHERE txs.tx_current <> ? AND txs.branch_id = ? AND txs.transaction_id <= ? ORDER BY txs.transaction_id DESC";
   private static final String INSERT_ADDRESSING =
      "INSERT INTO osee_txs (transaction_id, gamma_id, mod_type, tx_current, branch_id) VALUES (?,?,?,?,?)";
   private static final String USER_ID_QUERY = "SELECT art_id FROM osee_artifact WHERE guid = ?";

   private static final String MERGE_BRANCH_INSERT =
      "INSERT INTO osee_merge (source_branch_id, dest_branch_id, merge_branch_id, commit_transaction_id) VALUES (?,?,?,?)";

   private final static String SELECT_ATTRIBUTE_ADDRESSING_FROM_JOIN =
      "SELECT item.gamma_id, txs.mod_type FROM osee_attribute item, osee_txs txs, osee_join_artifact artjoin WHERE txs.branch_id = ? AND txs.tx_current <> ? AND txs.gamma_id = item.gamma_id AND item.art_id = artjoin.art_id and artjoin.query_id = ? ORDER BY txs.transaction_id DESC";
   private final static String SELECT_ARTIFACT_ADDRESSING_FROM_JOIN =
      "SELECT item.gamma_id, txs.mod_type FROM osee_artifact item, osee_txs txs, osee_join_artifact artjoin WHERE txs.branch_id = ? AND txs.tx_current <> ? AND txs.gamma_id = item.gamma_id AND item.art_id = artjoin.art_id and artjoin.query_id = ? ORDER BY txs.transaction_id DESC";

   private static final String TEST_MERGE_BRANCH_EXISTENCE =
      "SELECT COUNT(1) FROM osee_merge WHERE source_branch_id = ? AND dest_branch_id = ?";

   private boolean passedPreConditions;
   private boolean wasSuccessful;
   private int systemUserId;

   private final BranchCache branchCache;
   private final TransactionCache txCache;
   private final BranchFactory branchFactory;
   private final TransactionRecordFactory txFactory;
   private final CreateDatabaseBranch newBranchData;
   private Branch branch;

   public CreateBranchDatabaseTxCallable(Log logger, IOseeDatabaseService databaseService, BranchCache branchCache, TransactionCache txCache, BranchFactory branchFactory, TransactionRecordFactory txFactory, CreateDatabaseBranch newBranchData) {
      super(logger, databaseService, String.format("Create Branch: [%s from %s]", newBranchData.getBranchName(),
         newBranchData.getParentBranchId()));
      this.branchCache = branchCache;
      this.txCache = txCache;
      this.branchFactory = branchFactory;
      this.txFactory = txFactory;
      this.newBranchData = newBranchData;
      this.wasSuccessful = false;
      this.systemUserId = -1;
   }

   private int getSystemUserId() {
      if (systemUserId == -1) {
         try {
            systemUserId =
               getDatabaseService().runPreparedQueryFetchObject(-1, USER_ID_QUERY, SystemUser.OseeSystem.getGuid());
         } catch (OseeCoreException ex) {
            getLogger().warn(ex, "Unable to retrieve the system user");
         }
      }
      return systemUserId;
   }

   public void checkPreconditions(Branch parentBranch, Branch destinationBranch) throws OseeCoreException {
      if (newBranchData.getBranchType().isMergeBranch()) {
         if (getDatabaseService().runPreparedQueryFetchObject(0, TEST_MERGE_BRANCH_EXISTENCE, parentBranch.getId(),
            destinationBranch.getId()) > 0) {
            throw new OseeStateException("Existing merge branch detected for [%s] and [%s]", parentBranch.getName(),
               destinationBranch.getName());
         }
      } else if (!newBranchData.getBranchType().isSystemRootBranch()) {
         int associatedArtifactId = newBranchData.getAssociatedArtifactId();
         int systemUserId = getSystemUserId();
         if (associatedArtifactId > -1 && associatedArtifactId != systemUserId) {
            int count =
               getDatabaseService().runPreparedQueryFetchObject(0,
                  "SELECT (1) FROM osee_branch WHERE associated_art_id = ? AND branch_state NOT IN (?, ?)",
                  newBranchData.getAssociatedArtifactId(), BranchState.DELETED.getValue(),
                  BranchState.REBASELINED.getValue());
            if (count > 0) {
               throw new OseeStateException("Existing branch creation detected for [%s]", newBranchData.getBranchName());
            }
         }
      }
   }

   @SuppressWarnings("unchecked")
   @Override
   protected Branch handleTxWork(OseeConnection connection) throws OseeCoreException {
      Branch parentBranch = branchCache.getById(newBranchData.getParentBranchId());
      Branch destinationBranch = branchCache.getById(newBranchData.getMergeDestinationBranchId());

      passedPreConditions = false;
      checkPreconditions(parentBranch, destinationBranch);
      passedPreConditions = true;

      String guid = newBranchData.getBranchGuid();
      if (!GUID.isValid(guid)) {
         guid = GUID.create();
      }

      branch =
         branchFactory.create(guid, newBranchData.getBranchName(), newBranchData.getBranchType(),
            BranchState.CREATION_IN_PROGRESS, false);

      branch.setParentBranch(parentBranch);
      branch.setAssociatedArtifactId(newBranchData.getAssociatedArtifactId());

      Timestamp timestamp = GlobalTime.GreenwichMeanTimestamp();
      int nextTransactionId = getDatabaseService().getSequence().getNextTransactionId();

      if (branch.getBranchType().isSystemRootBranch()) {
         TransactionRecord systemTx =
            txFactory.create(nextTransactionId, branch.getId(), newBranchData.getCreationComment(), timestamp,
               newBranchData.getAuthorId(), -1, TransactionDetailsType.Baselined, branchCache);
         branch.setSourceTransaction(systemTx);
      } else {
         branch.setSourceTransaction(txCache.getOrLoad(newBranchData.getSourceTransactionId()));
      }

      if (branch.getBranchType().isMergeBranch()) {
         ((MergeBranch) branch).setSourceBranch(parentBranch);
         ((MergeBranch) branch).setDestinationBranch(destinationBranch);
      }

      branchCache.cache(branch);
      branchCache.storeItems(branch);

      getDatabaseService().runPreparedUpdate(connection, INSERT_TX_DETAILS, branch.getId(), nextTransactionId,
         newBranchData.getCreationComment(), timestamp, newBranchData.getAuthorId(),
         TransactionDetailsType.Baselined.getId());

      TransactionRecord record =
         txFactory.create(nextTransactionId, branch.getId(), newBranchData.getCreationComment(), timestamp,
            newBranchData.getAuthorId(), -1, TransactionDetailsType.Baselined, branchCache);

      if (branch.getBranchType().isSystemRootBranch()) {
         branch.setSourceTransaction(record);
      }
      branch.setBaseTransaction(record);
      txCache.cache(record);
      populateBaseTransaction(0.30, connection, branch, newBranchData.getMergeAddressingQueryId());

      addMergeBranchEntry(0.20, connection, branch, newBranchData.getMergeDestinationBranchId());
      wasSuccessful = true;
      return branch;
   }

   @Override
   protected void handleTxException(Exception ex) {
      if (passedPreConditions) {
         try {
            branch.setStorageState(StorageState.PURGED);
            branchCache.storeItems(branch);
         } catch (OseeCoreException ex1) {
            getLogger().error(ex1, "Error during create branch [%s]", branch);
         }
      }
   }

   @Override
   protected void handleTxFinally() throws OseeCoreException {
      if (wasSuccessful) {
         branch.setBranchState(BranchState.CREATED);
         branchCache.storeItems(branch);
      }
   }

   private void addMergeBranchEntry(double workAmount, OseeConnection connection, Branch branch, int destinationBranchId) throws OseeCoreException {
      if (branch.getBranchType().isMergeBranch()) {
         int parentBranchId = branch.hasParentBranch() ? branch.getParentBranch().getId() : -1;
         getDatabaseService().runPreparedUpdate(connection, MERGE_BRANCH_INSERT, parentBranchId,
            newBranchData.getMergeDestinationBranchId(), branch.getId(), 0);
      }
      checkForCancelled();
   }

   private void populateBaseTransaction(double workAmount, OseeConnection connection, Branch branch, int mergeAddressingQueryId) throws OseeCoreException {
      if (branch.getBranchType() != BranchType.SYSTEM_ROOT) {
         List<Object[]> data = new ArrayList<Object[]>();
         HashSet<Integer> gammas = new HashSet<Integer>(100000);
         int parentBranchId = -1;
         if (branch.hasParentBranch()) {
            parentBranchId = branch.getParentBranch().getId();
         }
         int baseTxId = branch.getBaseTransaction().getId();
         if (branch.getBranchType().isMergeBranch()) {
            populateAddressingToCopy(connection, data, baseTxId, gammas, SELECT_ATTRIBUTE_ADDRESSING_FROM_JOIN,
               parentBranchId, TxChange.NOT_CURRENT.getValue(), mergeAddressingQueryId);
            populateAddressingToCopy(connection, data, baseTxId, gammas, SELECT_ARTIFACT_ADDRESSING_FROM_JOIN,
               parentBranchId, TxChange.NOT_CURRENT.getValue(), mergeAddressingQueryId);
         } else {
            populateAddressingToCopy(connection, data, baseTxId, gammas, SELECT_ADDRESSING,
               TxChange.NOT_CURRENT.getValue(), parentBranchId, branch.getSourceTransaction().getId());
         }
         if (!data.isEmpty()) {
            getDatabaseService().runBatchUpdate(connection, INSERT_ADDRESSING, data);
         }
      }
      checkForCancelled();
   }

   private void populateAddressingToCopy(OseeConnection connection, List<Object[]> data, int baseTxId, HashSet<Integer> gammas, String query, Object... parameters) throws OseeCoreException {
      IOseeStatement chStmt = getDatabaseService().getStatement(connection);
      try {
         chStmt.runPreparedQuery(10000, query, parameters);
         while (chStmt.next()) {
            checkForCancelled();
            Integer gamma = chStmt.getInt("gamma_id");
            if (!gammas.contains(gamma)) {
               ModificationType modType = ModificationType.getMod(chStmt.getInt("mod_type"));
               TxChange txCurrent = TxChange.getCurrent(modType);
               data.add(new Object[] {baseTxId, gamma, modType.getValue(), txCurrent.getValue(), branch.getId()});
               gammas.add(gamma);
            }
         }
      } finally {
         chStmt.close();
      }
   }

}

Back to the top