Java tutorial
/* * Copyright 2009 CollabNet, Inc. ("CollabNet") Licensed under the Apache * License, Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law * or agreed to in writing, software distributed under the License is * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package com.collabnet.ccf.pi.qc.v90; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.collabnet.ccf.core.CCFRuntimeException; import com.collabnet.ccf.core.utils.DateUtil; import com.collabnet.ccf.pi.qc.v90.api.IBug; import com.collabnet.ccf.pi.qc.v90.api.IBugFactory; import com.collabnet.ccf.pi.qc.v90.api.IConnection; import com.collabnet.ccf.pi.qc.v90.api.IFactoryList; import com.collabnet.ccf.pi.qc.v90.api.IFilter; import com.collabnet.ccf.pi.qc.v90.api.IRecordSet; import com.collabnet.ccf.pi.qc.v90.api.IRequirement; import com.collabnet.ccf.pi.qc.v90.api.IRequirementsFactory; import com.collabnet.ccf.pi.qc.v90.api.dcom.Bug; import com.collabnet.ccf.pi.qc.v90.api.dcom.Requirement; /** * This class contains several methods that are used by QCHandler, * QCAttachmentHandler and QCWriter and are Generic so that some of the * functionalities could be reused in other components if necessary. They deal * with getting the defects, different fields from QC, writing into file and so * on. * * @author venugopala * */ public class QCGAHelper { public static class ArtifactInformation { public String lastTransactionId; public String lastModifiedBy; public Date creationDate; public Date lastModifiedDate; public String creationTransactionId; } private static final Log log = LogFactory.getLog(QCGAHelper.class); /** * Deletes the temporary file that was used to store the content of the data * and use the fileName of that temporary file to actually ship the * attachment(s). * */ public boolean deleteTempFile(String fileName) { File f = new File(fileName); // Make sure the file or directory exists and isn't write protected if (!f.exists()) throw new IllegalArgumentException("Delete: no such file or directory: " + fileName); if (!f.canWrite()) throw new IllegalArgumentException("Delete: write protected: " + fileName); // If it is a directory, make sure it is empty if (f.isDirectory()) { String[] files = f.list(); if (files.length > 0) throw new IllegalArgumentException("Delete: directory not empty: " + fileName); } // Attempt to delete it boolean success = f.delete(); if (!success) throw new IllegalArgumentException("Delete: deletion failed"); return success; } /** * Gets the BG_VTS value for the given defect from QC as the value is not * populated in the GenericArtifact * * @param qcc * @param actionId * @param entityId * @return */ public String findVtsFromQC(IConnection qcc, int actionId, int entityId) { String sql = "SELECT AU_TIME FROM AUDIT_LOG WHERE AU_ACTION_ID='" + actionId + "' AND AU_ACTION!='DELETE' AND AU_ENTITY_ID='" + entityId + "'"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); String auTime = newRs.getFieldValueAsString("AU_TIME"); return auTime; } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } } /** * Obtains the date at which the defect identified by the entityId was * created * * @param qcc * @param entityId * @return */ public Date getDefectCreatedDate(IConnection qcc, int entityId) { String sql = "SELECT AU_TIME FROM AUDIT_LOG WHERE AU_ENTITY_TYPE='BUG' AND AU_ACTION!='DELETE' AND AU_ENTITY_ID= '" + entityId + "'"; IRecordSet rs = null; String fieldValue = null; Date createdOn = new Date(); try { rs = qcc.executeSQL(sql); int rc = rs.getRecordCount(); for (int cnt = 0; cnt < rc; cnt++, rs.next()) { if (cnt == 0) { fieldValue = rs.getFieldValueAsString("AU_TIME"); break; } } } finally { if (rs != null) { rs.safeRelease(); rs = null; } } if (fieldValue != null) createdOn = DateUtil.parseQCDate(fieldValue); return createdOn; } /** * Fetches the QC defect given the connection object and the defect ID to be * fetched. * * @param qcc * The Connection object * @param id * The defect ID which needs to be fetched * @return QCDefect QCDefect object that represents a QC Defect * */ public QCDefect getDefectWithId(IConnection qcc, int id) { IBugFactory bf = null; IFilter filter = null; IFactoryList fl = null; IBug bug = null; try { bf = qcc.getBugFactory(); filter = bf.getFilter(); filter.setFilter(QCConfigHelper.bgBugIdFieldName, Integer.toString(id)); fl = filter.getNewList(); bug = fl.getBug(1); } catch (Exception e) { String message = "Exception caught in getDefectWithId of DefectHandler"; log.error(message); throw new CCFRuntimeException(message, e); } finally { if (fl != null) { fl.safeRelease(); } if (filter != null) { filter.safeRelease(); } bf = null; } QCDefect defect = new QCDefect((Bug) bug); return defect; } public String getDeletedAttachmentId(IConnection qcc, String entityId, String attachmentName, String deleteTransactionId) { String attachmentId = null; String sql = "SELECT AU_ENTITY_ID FROM AUDIT_LOG WHERE AU_FATHER_ID=" + deleteTransactionId + " AND AU_ENTITY_TYPE='CROS_REF' AND AU_DESCRIPTION LIKE '%" + qcc.sanitizeStringForSQLLikeQuery(attachmentName, "\\") + "' ESCAPE '\\' ORDER BY AU_ACTION_ID DESC"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); if (newRs != null && newRs.getRecordCount() != 0) { attachmentId = newRs.getFieldValueAsString("AU_ENTITY_ID"); } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } return attachmentId; } /** * Fetches the QC requirement given the connection object and the * requirement ID to be fetched. * * @param qcc * The Connection object * @param id * The requirement ID which needs to be fetched * @return QCDefect QCDefect object that represents a QC Defect * */ public QCRequirement getRequirementWithId(IConnection qcc, int id) { IRequirementsFactory rf = null; IFilter filter = null; IFactoryList fl = null; IRequirement requirement = null; try { rf = qcc.getRequirementsFactory(); filter = rf.getFilter(); filter.setFilter(QCConfigHelper.rqReqIdFieldName, Integer.toString(id)); fl = filter.getNewList(); requirement = fl.getRequirement(1); } catch (Exception e) { String message = "Exception caught in getRequirementWithId of QCHandler"; log.error(message); throw new CCFRuntimeException(message, e); } finally { if (fl != null) { fl.safeRelease(); } if (filter != null) { filter.safeRelease(); } rf = null; } QCRequirement req = new QCRequirement((Requirement) requirement); return req; } /** * Gets the value of the lastTransactionId of a defect and a list of * descriptions for attachments (if any) * * @param bugId * The defectId for which the search has to be made in QC * @param txnId * The transactionId starting from which the search has to be * made for a particular defectId in QC * @param upperTransactionId * @param qcc * The Connection object * @param connectorUser * The connectorUser name used while updating the comments * @param resyncUser * resync user name * @return List<Object> -> String TransactionId and List of attachment names * for the given defectId after the given transactionId */ public List<Object> getTxnIdAndAuDescriptionForDefect(String bugId, String txnId, String upperTransactionId, IConnection qcc, String connectorUser, String resyncUser) { List<Object> txnIdAndAuDescription = new ArrayList<Object>(); String transactionId = null; String modifiedBy = null; String resyncUserFilter = ""; if (!StringUtils.isEmpty(resyncUser)) { resyncUserFilter = "' and au_user !='" + resyncUser; } Map<String, Map<String, String>> addedAttachmentNames = new TreeMap<String, Map<String, String>>(); Map<String, Map<String, String>> deletedAttachmentNames = new TreeMap<String, Map<String, String>>(); String sql = "select AU_TIME, AU_ACTION_ID, AU_DESCRIPTION, AU_USER from audit_log where au_entity_id = '" + bugId //Removed and au_father_id='-1' + "' and au_action!='DELETE' and au_entity_type='BUG' and au_user !='" + connectorUser + resyncUserFilter + "' and au_action_id > '" + txnId + "' and au_action_id <= '" + upperTransactionId + "' order by au_action_id desc"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); log.debug("In QCHandler.getTxnIdAndAuDescriptionForDefect, sql=" + sql); if (newRc > 0) { for (int newCnt = 0; newCnt < newRc; newCnt++, newRs.next()) { if (newCnt == 0) { transactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); modifiedBy = newRs.getFieldValueAsString("AU_USER"); } String auDescription = newRs.getFieldValueAsString("AU_DESCRIPTION"); List<String> attachDescription = getAttachmentOperation(auDescription); if (attachDescription != null && attachDescription.size() > 0) { if (attachDescription.get(1) != null) { if (attachDescription.get(1).equals("added")) { String addTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); String addTime = newRs.getFieldValueAsString("AU_TIME"); Map<String, String> values = new TreeMap<String, String>(); values.put("AU_ACTION_ID", addTransactionId); values.put("AU_TIME", addTime); addedAttachmentNames.put(attachDescription.get(2), values); } else if (attachDescription.get(1).equals("deleted")) { String deleteTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); String deleteTime = newRs.getFieldValueAsString("AU_TIME"); Map<String, String> values = new TreeMap<String, String>(); values.put("AU_ACTION_ID", deleteTransactionId); values.put("AU_TIME", deleteTime); deletedAttachmentNames.put(attachDescription.get(2), values); } } } } } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } txnIdAndAuDescription.add((Object) transactionId); txnIdAndAuDescription.add((Object) addedAttachmentNames); txnIdAndAuDescription.add((Object) deletedAttachmentNames); txnIdAndAuDescription.add((Object) modifiedBy); return txnIdAndAuDescription; } /** * Gets the value of the lastTransactionId of a defect and a list of * descriptions for attachments (if any) * * @param requirementId * The requirement Id for which the search has to be made in QC * @param txnId * The transactionId starting from which the search has to be * made for a particular requirement id in QC * @param upperTransactionId * @param qcc * The Connection object * @param connectorUser * The connectorUser name used while updating the comments * @param resyncUser * resync user name * @return List<Object> -> String TransactionId and List of attachment names * for the given requirement id after the given transactionId */ public List<Object> getTxnIdAndAuDescriptionForRequirement(String requirementId, String txnId, String upperTransactionId, IConnection qcc, String connectorUser, String resyncUser) { List<Object> txnIdAndAuDescription = new ArrayList<Object>(); String transactionId = null; String modifiedBy = null; String resyncUserFilter = ""; if (!StringUtils.isEmpty(resyncUser)) { resyncUserFilter = "' and au_user !='" + resyncUser; } Map<String, Map<String, String>> addedAttachmentNames = new TreeMap<String, Map<String, String>>(); Map<String, Map<String, String>> deletedAttachmentNames = new TreeMap<String, Map<String, String>>(); // this property decides whether artifact can already be returned or whether attachment transactions are still not completed due to missing check in boolean shipArtifact = false; String sql = "select AU_TIME, AU_ACTION_ID, AU_DESCRIPTION, AU_USER from audit_log where au_entity_id = '" + requirementId //Removed and au_father_id='-1' + "' and au_action!='DELETE' and au_entity_type='REQ' and au_user !='" + connectorUser + resyncUserFilter + "' and au_action_id > '" + txnId + "' and au_action_id <= '" + upperTransactionId + "' order by au_action_id desc"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); log.debug("In QCHandler.getTxnIdAndAuDescriptionForRequirement, sql=" + sql); if (newRc > 0) { for (int newCnt = 0; newCnt < newRc; newCnt++, newRs.next()) { if (!shipArtifact) { transactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); modifiedBy = newRs.getFieldValueAsString("AU_USER"); } String auDescription = newRs.getFieldValueAsString("AU_DESCRIPTION"); List<String> attachDescription = getAttachmentOperation(auDescription); if (attachDescription != null && attachDescription.size() > 0) { if (attachDescription.get(1) != null) { if (attachDescription.get(1).equals("added")) { String attachmentName = attachDescription.get(2); // here we have to check whether attachment already exists if (getFromTable(qcc, requirementId, attachmentName) != null) { String addTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); String addTime = newRs.getFieldValueAsString("AU_TIME"); Map<String, String> values = new TreeMap<String, String>(); values.put("AU_ACTION_ID", addTransactionId); values.put("AU_TIME", addTime); addedAttachmentNames.put(attachmentName, values); shipArtifact = true; } else { log.debug("Looks as if attachment transaction has not yet completed."); } } else if (attachDescription.get(1).equals("deleted")) { String attachmentName = attachDescription.get(2); // here we have to check whether attachment still exists if (getFromTable(qcc, requirementId, attachmentName) == null) { String deleteTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); String deleteTime = newRs.getFieldValueAsString("AU_TIME"); Map<String, String> values = new TreeMap<String, String>(); values.put("AU_ACTION_ID", deleteTransactionId); values.put("AU_TIME", deleteTime); deletedAttachmentNames.put(attachDescription.get(2), values); shipArtifact = true; } else { log.debug("Looks as if attachment transaction has not yet completed."); } } else { shipArtifact = true; } } } else { shipArtifact = true; } } } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } if (shipArtifact) { txnIdAndAuDescription.add((Object) transactionId); txnIdAndAuDescription.add((Object) addedAttachmentNames); txnIdAndAuDescription.add((Object) deletedAttachmentNames); txnIdAndAuDescription.add((Object) modifiedBy); return txnIdAndAuDescription; } else { return null; } } /** * Stores the incoming data with the given file name * * @param data * array The data to be stored * @param fileName * The Name of the file in a temp Dir to hold the data * @return File object Pointing to the created File * */ public File writeDataIntoFile(byte[] data, String fileName) { File attachmentFile = null; String tempDir = System.getProperty("java.io.tmpdir"); attachmentFile = new File(tempDir, fileName); try { FileOutputStream fs = new FileOutputStream(attachmentFile); fs.write(data); fs.close(); } catch (Exception e) { log.error("Exception while writing the byte array into the file", e); } return attachmentFile; } /** * Copy a file from origin to target * * @param origin * origin file * @param target * target file */ public static void copyFile(File origin, File target) { try { FileInputStream fis = new FileInputStream(origin); FileOutputStream fos = new FileOutputStream(target); int readCount = 0; byte[] tmpData = new byte[1024 * 4]; while ((readCount = fis.read(tmpData)) != -1) { fos.write(tmpData, 0, readCount); } fis.close(); fos.close(); } catch (FileNotFoundException e) { String message = "Could not read attachment content." + " File not found " + origin.getAbsolutePath(); log.error(message, e); throw new CCFRuntimeException(message, e); } catch (IOException e) { String message = "Could not read attachment content." + " IOException while reading " + origin.getAbsolutePath(); log.error(message, e); throw new CCFRuntimeException(message, e); } } /** * Gets the exact operation of the attachment i.e, added, deleted or updated * * @param auDescription * This is the field denoting the attachment operation in * CROS_REF table of QC. * @return List<String> This list contains 1. attachLabel ("attachment") 2. * exact operation("added" or "updated") 3. attachment ID */ public static List<String> getAttachmentOperation(String auDescription) { List<String> attachDescription = new ArrayList<String>(); if (auDescription != null && auDescription.startsWith("Attachment")) { int colonPosition = auDescription.indexOf(": "); String attachLabelAndOperation = auDescription.substring(0, colonPosition); String crReference = auDescription.substring(colonPosition + 2, auDescription.length()); /* * StringTokenizer st = new StringTokenizer(auDescription, ": "); * String attachLabelAndOperation = st.nextToken().trim(); String * crReference = st.nextToken().trim(); */ StringTokenizer newSt = new StringTokenizer(attachLabelAndOperation, " "); String attachLabel = newSt.nextToken().trim(); attachDescription.add(attachLabel); String operation = newSt.nextToken().trim(); attachDescription.add(operation); attachDescription.add(crReference); log.debug(attachDescription); // if (operation.equals("added")) // return attachDescription; } return attachDescription; } public static ArtifactInformation getDefectInformation(IConnection qcc, String artifactId, String txnId) { String artifactType = "BUG"; ArtifactInformation res = new ArtifactInformation(); //Removed and au_father_id='-1' String sql = "select AU_TIME, AU_ACTION_ID, AU_DESCRIPTION, AU_USER from audit_log where au_entity_id = '" + artifactId //Removed and au_father_id='-1' + "' and au_action!='DELETE' and au_entity_type='BUG' and au_action_id > '" + txnId + "' order by au_action_id desc"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); log.debug("In QCHandler.getTxnIdAndAuDescriptionForDefect, sql=" + sql); if (newRc > 0) { res.lastTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); res.lastModifiedBy = newRs.getFieldValueAsString("AU_USER"); String auTimeStr = newRs.getFieldValueAsString("AU_TIME"); res.lastModifiedDate = DateUtil.parseQCDate(auTimeStr); } else { log.warn(String.format("could not retrieve information for artifact id '%s'", artifactId)); } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } try { // retrieve the object creation date sql = String.format("select AU_TIME, AU_ACTION_ID from AUDIT_LOG" + " where au_entity_id = '%s' and au_action!='DELETE' and au_entity_type='%s' " + " order by au_action_id asc", artifactId, artifactType); newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); if (newRc > 0) { String creationDate = newRs.getFieldValueAsString("AU_TIME"); res.creationDate = DateUtil.parseQCDate(creationDate); res.creationTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } return res; } /** * Obtains the attachment ID, attachment Type (data or link) and attachment * description for a given entity * * @param qcc * @param entityId * @param attachmentName * @return */ public static List<String> getFromTable(IConnection qcc, String entityId, String attachmentName) { List<String> attachmentDetails = null; String sql = "SELECT CR_REF_ID, CR_REF_TYPE, CR_DESCRIPTION FROM CROS_REF WHERE CR_KEY_1='" + entityId + "' AND CR_REFERENCE like '%" + qcc.sanitizeStringForSQLLikeQuery(attachmentName, "\\") + "%' ESCAPE '\\' ORDER BY CR_REF_ID DESC"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); if (newRs != null && newRs.getRecordCount() != 0) { attachmentDetails = new ArrayList<String>(); String crRefId = newRs.getFieldValueAsString("CR_REF_ID"); attachmentDetails.add(crRefId); String crRefType = newRs.getFieldValueAsString("CR_REF_TYPE"); attachmentDetails.add(crRefType); String crDescription = newRs.getFieldValueAsString("CR_DESCRIPTION"); attachmentDetails.add(crDescription); } } finally { if (newRs != null) { newRs.safeRelease(); } } return attachmentDetails; } public static ArtifactInformation getRequirementInformation(IConnection qcc, String requirementId, String txnId) { ArtifactInformation res = new ArtifactInformation(); // this property decides whether artifact can already be returned or whether attachment transactions are still not completed due to missing check in boolean shipArtifact = false; String sql = "select AU_TIME, AU_ACTION_ID, AU_DESCRIPTION, AU_USER from audit_log where au_entity_id = '" + requirementId //Removed and au_father_id='-1' + "' and au_action!='DELETE' and au_entity_type='REQ' and au_action_id > '" + txnId + "' order by au_action_id desc"; IRecordSet newRs = null; try { newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); log.debug("In QCHandler.getTxnIdAndAuDescriptionForRequirement, sql=" + sql); if (newRc > 0) { for (int newCnt = 0; newCnt < newRc; newCnt++, newRs.next()) { if (!shipArtifact) { res.lastTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); res.lastModifiedBy = newRs.getFieldValueAsString("AU_USER"); res.lastModifiedDate = DateUtil.parseQCDate(newRs.getFieldValueAsString("AU_TIME")); } String auDescription = newRs.getFieldValueAsString("AU_DESCRIPTION"); List<String> attachDescription = getAttachmentOperation(auDescription); if (attachDescription != null && attachDescription.size() > 0) { if (attachDescription.get(1) != null) { if (attachDescription.get(1).equals("added")) { String attachmentName = attachDescription.get(2); // here we have to check whether attachment already exists if (getFromTable(qcc, requirementId, attachmentName) != null) { shipArtifact = true; } else { log.debug("Looks as if attachment transaction has not yet completed."); } } else if (attachDescription.get(1).equals("deleted")) { String attachmentName = attachDescription.get(2); // here we have to check whether attachment still exists if (getFromTable(qcc, requirementId, attachmentName) == null) { shipArtifact = true; } else { log.debug("Looks as if attachment transaction has not yet completed."); } } else { shipArtifact = true; } } } else { shipArtifact = true; } } } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } if (!shipArtifact) { return null; } try { // retrieve the object creation date sql = String.format("select AU_TIME, AU_ACTION_ID from AUDIT_LOG" + " where au_entity_id = '%s' and au_action!='DELETE' and au_entity_type='%s' " + " order by au_action_id asc", requirementId, "REQ"); newRs = qcc.executeSQL(sql); int newRc = newRs.getRecordCount(); if (newRc > 0) { String creationDate = newRs.getFieldValueAsString("AU_TIME"); res.creationDate = DateUtil.parseQCDate(creationDate); res.creationTransactionId = newRs.getFieldValueAsString("AU_ACTION_ID"); } } finally { if (newRs != null) { newRs.safeRelease(); newRs = null; } } return res; } }