| /******************************************************************************* |
| * 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.framework.skynet.core.artifact; |
| |
| import static org.eclipse.osee.framework.core.enums.DeletionFlag.EXCLUDE_DELETED; |
| import static org.eclipse.osee.framework.core.enums.DeletionFlag.INCLUDE_DELETED; |
| import static org.eclipse.osee.framework.skynet.core.artifact.LoadType.INCLUDE_CACHE; |
| import static org.eclipse.osee.framework.skynet.core.artifact.LoadType.RELOAD_CACHE; |
| import java.sql.Timestamp; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Random; |
| import java.util.logging.Level; |
| import org.eclipse.osee.framework.core.client.ClientSessionManager; |
| import org.eclipse.osee.framework.core.data.IArtifactType; |
| import org.eclipse.osee.framework.core.data.IOseeBranch; |
| import org.eclipse.osee.framework.core.enums.DeletionFlag; |
| import org.eclipse.osee.framework.core.enums.ModificationType; |
| import org.eclipse.osee.framework.core.exception.OseeCoreException; |
| import org.eclipse.osee.framework.core.exception.OseeDataStoreException; |
| import org.eclipse.osee.framework.core.model.Branch; |
| import org.eclipse.osee.framework.core.model.TransactionRecord; |
| import org.eclipse.osee.framework.database.core.ConnectionHandler; |
| import org.eclipse.osee.framework.database.core.IOseeStatement; |
| import org.eclipse.osee.framework.database.core.OseeConnection; |
| import org.eclipse.osee.framework.database.core.OseeSql; |
| import org.eclipse.osee.framework.database.core.SQL3DataType; |
| import org.eclipse.osee.framework.jdk.core.type.CompositeKeyHashMap; |
| import org.eclipse.osee.framework.jdk.core.util.Lib; |
| import org.eclipse.osee.framework.jdk.core.util.time.GlobalTime; |
| import org.eclipse.osee.framework.logging.OseeLog; |
| import org.eclipse.osee.framework.skynet.core.internal.Activator; |
| |
| /** |
| * @author Ryan D. Brooks |
| */ |
| public final class ArtifactLoader { |
| |
| private static final String INSERT_JOIN_ARTIFACT = |
| "INSERT INTO osee_join_artifact (query_id, insert_time, art_id, branch_id, transaction_id) VALUES (?, ?, ?, ?, ?)"; |
| private static final String DELETE_FROM_JOIN_ARTIFACT = "DELETE FROM osee_join_artifact WHERE query_id = ?"; |
| |
| /** |
| * (re)loads the artifacts selected by sql and then returns them in a list |
| */ |
| public static List<Artifact> getArtifacts(String sql, Object[] queryParameters, int artifactCountEstimate, LoadLevel loadLevel, LoadType reload, ISearchConfirmer confirmer, TransactionRecord transactionId, DeletionFlag allowDeleted) throws OseeCoreException { |
| List<Artifact> artifacts = new ArrayList<Artifact>(artifactCountEstimate); |
| int queryId = getNewQueryId(); |
| CompositeKeyHashMap<Integer, Integer, Object[]> insertParameters = |
| new CompositeKeyHashMap<Integer, Integer, Object[]>(artifactCountEstimate, false); |
| selectArtifacts(artifacts, queryId, insertParameters, sql, queryParameters, artifactCountEstimate, transactionId, |
| reload); |
| |
| boolean historical = transactionId != null; |
| if (!insertParameters.isEmpty()) { |
| artifacts.addAll(loadArtifacts(queryId, loadLevel, confirmer, |
| new ArrayList<Object[]>(insertParameters.values()), reload, historical, allowDeleted)); |
| } else if (confirmer != null) { |
| confirmer.canProceed(artifacts.size()); |
| } |
| return artifacts; |
| } |
| |
| public static List<Artifact> loadArtifactsFromQueryId(int queryId, LoadLevel loadLevel, ISearchConfirmer confirmer, int fetchSize, LoadType reload, boolean historical, DeletionFlag allowDeleted) throws OseeCoreException { |
| List<Artifact> loadedItems = new ArrayList<Artifact>(fetchSize); |
| loadArtifactsFromQueryId(loadedItems, queryId, loadLevel, confirmer, fetchSize, reload, historical, allowDeleted); |
| return loadedItems; |
| } |
| |
| private static void loadArtifactsFromQueryId(Collection<Artifact> loadedItems, int queryId, LoadLevel loadLevel, ISearchConfirmer confirmer, int fetchSize, LoadType reload, boolean historical, DeletionFlag allowDeleted) throws OseeCoreException { |
| try { |
| OseeSql sqlKey; |
| if (historical) { |
| sqlKey = OseeSql.LOAD_HISTORICAL_ARTIFACTS; |
| } else if (allowDeleted == INCLUDE_DELETED) { |
| sqlKey = OseeSql.LOAD_CURRENT_ARTIFACTS_WITH_DELETED; |
| } else { |
| sqlKey = OseeSql.LOAD_CURRENT_ARTIFACTS; |
| } |
| |
| IOseeStatement chStmt = ConnectionHandler.getStatement(); |
| |
| String sql = null; |
| try { |
| sql = ClientSessionManager.getSql(sqlKey); |
| chStmt.runPreparedQuery(fetchSize, sql, queryId); |
| |
| int previousArtId = -1; |
| int previousBranchId = -1; |
| while (chStmt.next()) { |
| int artId = chStmt.getInt("art_id"); |
| int branchId = chStmt.getInt("branch_id"); |
| // assumption: sql is returning rows ordered by branch_id, art_id, transaction_id in descending order |
| if (previousArtId != artId || previousBranchId != branchId) { |
| // assumption: sql is returning unwanted deleted artifacts only in the historical case |
| if (!historical || allowDeleted == INCLUDE_DELETED || ModificationType.getMod(chStmt.getInt("mod_type")) != ModificationType.DELETED) { |
| loadedItems.add(retrieveShallowArtifact(chStmt, reload, historical)); |
| } |
| } |
| previousArtId = artId; |
| previousBranchId = branchId; |
| } |
| } catch (OseeDataStoreException ex) { |
| OseeLog.log(Activator.class, Level.SEVERE, |
| String.format("%s - %s", sqlKey, sql == null ? "SQL unknown" : sql), ex); |
| throw ex; |
| } finally { |
| chStmt.close(); |
| } |
| |
| if (confirmer == null || confirmer.canProceed(loadedItems.size())) { |
| loadArtifactsData(queryId, loadedItems, loadLevel, reload, historical, allowDeleted); |
| |
| if (!historical) { |
| for (Artifact artifact : loadedItems) { |
| ArtifactCache.cacheByStaticId(artifact); |
| } |
| } |
| } |
| } finally { |
| clearQuery(queryId); |
| } |
| } |
| |
| public static List<Artifact> loadArtifacts(Collection<Integer> artIds, IOseeBranch branch, LoadLevel loadLevel, LoadType reload, DeletionFlag allowDeleted) throws OseeCoreException { |
| return loadArtifacts(artIds, branch, loadLevel, null, reload, allowDeleted); |
| } |
| |
| private static void checkArtifactCache(ArrayList<Artifact> artifacts, Collection<Integer> artIds, TransactionRecord transactionId, IOseeBranch branch, DeletionFlag allowDeleted) throws OseeCoreException { |
| Iterator<Integer> iterator = artIds.iterator(); |
| while (iterator.hasNext()) { |
| Integer artId = iterator.next(); |
| Artifact artifact = getArtifactFromCache(artId, transactionId, branch); |
| |
| if (artifact != null) { |
| if (allowDeleted == EXCLUDE_DELETED && artifact.isDeleted()) { |
| continue; |
| } |
| iterator.remove(); |
| artifacts.add(artifact); |
| } |
| } |
| } |
| |
| private static Artifact getArtifactFromCache(Integer artId, TransactionRecord transactionId, IOseeBranch branch) throws OseeCoreException { |
| boolean historical = transactionId != null; |
| if (historical) { |
| return ArtifactCache.getHistorical(artId, transactionId.getId()); |
| } |
| return ArtifactCache.getActive(artId, branch); |
| } |
| |
| /** |
| * loads or reloads artifacts based on artifact ids and branch ids |
| */ |
| public static List<Artifact> loadArtifacts(Collection<Integer> artIds, IOseeBranch branch, LoadLevel loadLevel, TransactionRecord transactionId, LoadType reload, DeletionFlag allowDeleted) throws OseeCoreException { |
| ArrayList<Artifact> artifacts = new ArrayList<Artifact>(); |
| |
| checkArtifactCache(artifacts, artIds, transactionId, branch, allowDeleted); |
| if (artIds != null && !artIds.isEmpty()) { |
| int queryId = ArtifactLoader.getNewQueryId(); |
| Timestamp insertTime = GlobalTime.GreenwichMeanTimestamp(); |
| boolean historical = transactionId != null; |
| |
| List<Object[]> insertParameters = new LinkedList<Object[]>(); |
| |
| for (int artId : org.eclipse.osee.framework.jdk.core.util.Collections.unique(artIds)) { |
| insertParameters.add(new Object[] { |
| queryId, |
| insertTime, |
| artId, |
| BranchManager.getBranchId(branch), |
| historical ? transactionId.getId() : SQL3DataType.INTEGER}); |
| } |
| |
| for (Artifact artifact : loadArtifacts(queryId, loadLevel, null, insertParameters, reload, historical, |
| allowDeleted)) { |
| artifacts.add(artifact); |
| } |
| } |
| return artifacts; |
| } |
| |
| /** |
| * loads or reloads artifacts based on artifact ids and branch ids in the insertParameters |
| */ |
| public static List<Artifact> loadArtifacts(int queryId, LoadLevel loadLevel, ISearchConfirmer confirmer, List<Object[]> insertParameters, LoadType reload, boolean historical, DeletionFlag allowDeleted) throws OseeCoreException { |
| List<Artifact> loadedItems = new ArrayList<Artifact>(insertParameters.size()); |
| loadArtifacts(loadedItems, queryId, loadLevel, confirmer, insertParameters, reload, historical, allowDeleted); |
| return loadedItems; |
| } |
| |
| public static void loadArtifacts(Collection<Artifact> loadedItems, int queryId, LoadLevel loadLevel, ISearchConfirmer confirmer, List<Object[]> insertParameters, LoadType reload, boolean historical, DeletionFlag allowDeleted) throws OseeCoreException { |
| if (!insertParameters.isEmpty()) { |
| Collection<Artifact> data; |
| if (loadedItems.isEmpty()) { |
| data = loadedItems; |
| } else { |
| // Use a new list if loaded items already contains data to prevent artifact overwrites during loading |
| data = new ArrayList<Artifact>(insertParameters.size()); |
| } |
| long time = System.currentTimeMillis(); |
| try { |
| insertIntoArtifactJoin(insertParameters); |
| loadArtifactsFromQueryId(data, queryId, loadLevel, confirmer, insertParameters.size(), reload, historical, |
| allowDeleted); |
| } finally { |
| if (data != loadedItems) { |
| loadedItems.addAll(data); |
| } |
| OseeLog.log( |
| Activator.class, |
| Level.FINE, |
| String.format("Artifact Load Time [%s] for [%d] artifacts. ", Lib.getElapseString(time), |
| loadedItems.size()), new Exception("Artifact Load Time")); |
| clearQuery(queryId); |
| } |
| } |
| } |
| |
| /** |
| * must be call in a try block with a finally clause which calls clearQuery() |
| */ |
| public static int insertIntoArtifactJoin(OseeConnection connection, List<Object[]> insertParameters) throws OseeCoreException { |
| return ConnectionHandler.runBatchUpdate(connection, INSERT_JOIN_ARTIFACT, insertParameters); |
| } |
| |
| /** |
| * must be call in a try block with a finally clause which calls clearQuery() |
| */ |
| public static int insertIntoArtifactJoin(List<Object[]> insertParameters) throws OseeCoreException { |
| return insertIntoArtifactJoin(null, insertParameters); |
| } |
| |
| /** |
| * should only be used in tandem with with selectArtifacts() |
| * |
| * @param queryId value gotten from call to getNewQueryId and used in populating the insert parameters for |
| * selectArtifacts |
| */ |
| public static void clearQuery(int queryId) throws OseeCoreException { |
| ConnectionHandler.runPreparedUpdate(DELETE_FROM_JOIN_ARTIFACT, queryId); |
| } |
| |
| /** |
| * should only be used in tandem with with selectArtifacts() |
| * |
| * @param queryId value gotten from call to getNewQueryId and used in populating the insert parameters for |
| * selectArtifacts |
| */ |
| public static void clearQuery(OseeConnection connection, int queryId) throws OseeCoreException { |
| if (connection != null) { |
| ConnectionHandler.runPreparedUpdate(connection, DELETE_FROM_JOIN_ARTIFACT, queryId); |
| } else { |
| ConnectionHandler.runPreparedUpdate(DELETE_FROM_JOIN_ARTIFACT, queryId); |
| } |
| } |
| |
| /** |
| * Populates artifacts with any artifact already in cache and populates insertParameters with necessary data to load |
| * the rest. |
| * |
| * @param reload will attempt to use cache if INCLUDE_CACHE |
| * @param insertParameters populated by this method |
| */ |
| private static void selectArtifacts(List<Artifact> artifacts, int queryId, CompositeKeyHashMap<Integer, Integer, Object[]> insertParameters, String sql, Object[] queryParameters, int artifactCountEstimate, TransactionRecord transactionId, LoadType reload) throws OseeCoreException { |
| IOseeStatement chStmt = ConnectionHandler.getStatement(); |
| long time = System.currentTimeMillis(); |
| |
| try { |
| chStmt.runPreparedQuery(artifactCountEstimate, sql, queryParameters); |
| Timestamp insertTime = GlobalTime.GreenwichMeanTimestamp(); |
| |
| while (chStmt.next()) { |
| int artId = chStmt.getInt("art_id"); |
| int branchId = chStmt.getInt("branch_id"); |
| Artifact artifact = getArtifactFromCache(artId, transactionId, BranchManager.getBranch(branchId)); |
| if (artifact != null && reload == LoadType.INCLUDE_CACHE) { |
| artifacts.add(artifact); |
| } else { |
| Object transactionParameter = transactionId == null ? SQL3DataType.INTEGER : transactionId.getId(); |
| insertParameters.put(artId, branchId, new Object[] { |
| queryId, |
| insertTime, |
| artId, |
| branchId, |
| transactionParameter}); |
| } |
| } |
| } finally { |
| chStmt.close(); |
| } |
| OseeLog.log(Activator.class, Level.FINE, String.format("Artifact Selection Time [%s], [%d] artifacts selected", |
| Lib.getElapseString(time), insertParameters.size()), new Exception("Artifact Selection Time")); |
| } |
| |
| private static Artifact retrieveShallowArtifact(IOseeStatement chStmt, LoadType reload, boolean historical) throws OseeCoreException { |
| int artifactId = chStmt.getInt("art_id"); |
| Branch branch = BranchManager.getBranch(chStmt.getInt("branch_id")); |
| Artifact artifact; |
| int transactionId = Artifact.TRANSACTION_SENTINEL; |
| if (historical) { |
| int stripeTransactionNumber = chStmt.getInt("stripe_transaction_id"); |
| transactionId = stripeTransactionNumber; |
| artifact = ArtifactCache.getHistorical(artifactId, stripeTransactionNumber); |
| } else { |
| artifact = ArtifactCache.getActive(artifactId, branch); |
| } |
| |
| if (artifact == null) { |
| IArtifactType artifactType = ArtifactTypeManager.getType(chStmt.getInt("art_type_id")); |
| ArtifactFactory factory = ArtifactTypeManager.getFactory(artifactType); |
| |
| artifact = |
| factory.loadExisitingArtifact(artifactId, chStmt.getString("guid"), chStmt.getString("human_readable_id"), |
| artifactType, chStmt.getInt("gamma_id"), branch, transactionId, |
| ModificationType.getMod(chStmt.getInt("mod_type")), historical); |
| |
| } else if (reload == RELOAD_CACHE) { |
| artifact.internalSetPersistenceData(chStmt.getInt("gamma_id"), transactionId, |
| ModificationType.getMod(chStmt.getInt("mod_type")), historical); |
| } |
| return artifact; |
| } |
| |
| @SuppressWarnings("unchecked") |
| static void loadArtifactData(Artifact artifact, LoadLevel loadLevel) throws OseeCoreException { |
| int queryId = getNewQueryId(); |
| Timestamp insertTime = GlobalTime.GreenwichMeanTimestamp(); |
| |
| try { |
| ConnectionHandler.runPreparedUpdate(INSERT_JOIN_ARTIFACT, queryId, insertTime, artifact.getArtId(), |
| artifact.getBranch().getId(), SQL3DataType.INTEGER); |
| |
| List<Artifact> artifacts = new ArrayList<Artifact>(1); |
| artifacts.add(artifact); |
| loadArtifactsData(queryId, artifacts, loadLevel, INCLUDE_CACHE, false, |
| artifact.isDeleted() ? INCLUDE_DELETED : EXCLUDE_DELETED); |
| } finally { |
| clearQuery(queryId); |
| } |
| } |
| |
| private static void loadArtifactsData(int queryId, Collection<Artifact> artifacts, LoadLevel loadLevel, LoadType reload, boolean historical, DeletionFlag allowDeleted) throws OseeCoreException { |
| if (reload == RELOAD_CACHE) { |
| for (Artifact artifact : artifacts) { |
| artifact.prepareForReload(); |
| } |
| } |
| |
| AttributeLoader.loadAttributeData(queryId, artifacts, historical, allowDeleted, loadLevel); |
| RelationLoader.loadRelationData(queryId, artifacts, historical, loadLevel); |
| |
| for (Artifact artifact : artifacts) { |
| artifact.onInitializationComplete(); |
| } |
| } |
| |
| public static int getNewQueryId() { |
| return new Random().nextInt(Integer.MAX_VALUE); |
| } |
| } |