Rev 4285 | Blame | Compare with Previous | Last modification | View Log | RSS feed
package com.erggroup.buildtool.ripple;import java.io.File;import java.sql.SQLException;import java.util.Iterator;import java.util.Vector;import org.apache.log4j.Logger;import com.erggroup.buildtool.smtp.Smtpsend;public class Package{/*** name of package, must not contain spaces** @attribute*/String mName = new String();/*** package scope** @attribute*/String mExtension = new String();/*** instance identifier** @attribute*/String mVersion = new String();/*** Version string as specified by the user. Used with a ripple type of 'F'*/String mFixedVersion = new String();/*** unique identifier for daemon builds = mName + mExtension for escrow* builds = mName + mVersion + mExtension** @attribute*/String mAlias = new String();/*** Version Control System Tag** @attribute*/String mVcsTag = new String();/*** build standards** @attribute*/Vector<BuildStandard> mBuildStandardCollection = new Vector<BuildStandard>();/*** GBE_MACHTYPE used to build generic packages for this baseline only has* meaning in the daemon build, not the escrow build accessed by* BuildStandard::getPlatform, getBuildStandard** @attribute*/public static final String mGenericMachtype = System.getenv("GBE_MACHTYPE");/*** build dependencies by package alias** @attribute*/Vector<String> mDependencyCollection = new Vector<String>();/*** primary package version key pv_id in database** @attribute*/int mId;/*** indication of the nature of change** @attribute*/Package.VersionNumberingStandard mChangeType = new VersionNumberingStandard();/*** determines what field is rippled on a package version whose dependencies* have changed** @attribute*/Package.VersionNumberingStandard mRippleField = new VersionNumberingStandard();/*** interested owners** @attribute*/private Vector<String> mBuildFailureEmailCollection = new Vector<String>();/*** when true will trigger unit tests as part of the package build phase in* daemon mode** @attribute*/boolean mHasAutomatedUnitTests = false;/*** when true, do not ripple this package through packages which are* dependent upon it in daemon mode** @attribute*/boolean mAdvisoryRipple = false;/*** determines the build file the package is built in, or not 1 Post Plan:* buildfile - Result of planning 2 Post Plan: Future build requirement 3* Post Plan: Package has no build requiremnt 0 not yet processed (initial* value) -1 not reproducible -2 not reproducible on the build platforms* configured for this release -3 do not ripple -4 directly dependent on* package versions not in the baseline -5 indirectly dependent on package* versions which are not reproducible because of -1, -2 (escrow), -3* (daemon), -4, -6 -6 circular dependency** @attribute*/int mBuildFile = 0;/*** build dependencies by package** @attribute*/Vector<Package> mPackageDependencyCollection = new Vector<Package>();/*** used for escrow build purposes set true when a package has been processed** @attribute*/boolean mProcessed = false;/*** set true for WIP package versions only used in daemon mode** @attribute*/boolean mDirectlyPlanned = false;/*** set true when it is determined to be ripple built** @attribute*/boolean mIndirectlyPlanned = false;/*** non zero instruction number when it is determined to be ripple built by* force** @attribute*/int mForcedRippleInstruction = 0;/*** non zero instruction number when it is determined to be test built** @attribute*/int mTestBuildInstruction = 0;/*** test build email destination** @attribute*/String mTestBuildEmail;/*** Version Control System Tag** @attribute*/String mTestBuildVcsTag = new String();/*** build standards** @attribute*/Vector<BuildStandard> mTestBuildStandardCollection = new Vector<BuildStandard>();/*** build dependencies by package alias** @attribute*/Vector<String> mTestBuildDependencyCollection = new Vector<String>();/*** build dependencies by pv_id (-1 or not used for planned dependencies)** @attribute*/Vector<Integer> mDependencyIDCollection = new Vector<Integer>();/*** unique pkg_id in the database used for querying package version existence* in the database in daemon mode** @attribute*/int mPid;/*** maximum major number supported for determining ripple number** @attribute*/int mMajorLimit;/*** maximum minor number supported for determining ripple number** @attribute*/int mMinorLimit;/*** maximum patch number supported for determining ripple number** @attribute*/int mPatchLimit;/*** maximum build number number supported for determining ripple number** @attribute*/int mBuildLimit;/*** Logger** @attribute*/private static final Logger mLogger = Logger.getLogger(Package.class);/*** dpkg archive location** @attribute*/public static final String mGbeDpkg = System.getenv("GBE_DPKG");/*** Exception message used upon detection an archive does not exist Seems* this is a rare but transient and recoverable scenario** @attribute*/public static final String mRecoverable = "dpkg_archive does not exist, recovery will be attempted";/*** true if the package exists in the package archive (dpkg_archive)** @attribute*/private boolean mArchivalExistence = true;/*** when true will trigger source control interaction eg labelling** @attribute*/public boolean mRequiresSourceControlInteraction = true;/*** when true has been checked for circular dependency** @attribute*/boolean mCheckedCircularDependency = false;/*** when true has circular dependency** @attribute*/boolean mHasCircularDependency = false;/*** constructor*/Package(int pv_id, String pkg_name, String v_ext, String alias, String pkg_vcs_tag, char change_type,char ripple_field, String pkg_version){mLogger.debug("Package 1: pv_id " + pv_id + " pkg_name " + pkg_name + " v_ext " + v_ext + " alias " + alias+ " pkg_vcs_tag " + pkg_vcs_tag + " change_type " + change_type);mId = pv_id;mName = pkg_name;mVersion = "0.0.0000";mExtension = v_ext;mAlias = alias;mVcsTag = pkg_vcs_tag;// Must not have any extensionmFixedVersion = pkg_version;mFixedVersion = mFixedVersion.substring(0, mFixedVersion.length() - mExtension.length());if (change_type == 'M'){// a ripple_field of 'L' indicates this package has limited version// numberingmChangeType.setMajor(ripple_field == 'L' ? true : false);} else if (change_type == 'N'){mChangeType.setMinor(ripple_field == 'L' ? true : false);} else if (change_type == 'P'){mChangeType.setPatch(ripple_field == 'L' ? true : false);} else if (change_type == 'F'){mChangeType.setFixed();} else{mChangeType.setUnknown();}}/*** constructor*/Package(int pv_id, String pkg_name, String pkg_version, String v_ext, String alias, String pkg_vcs_tag,char ripple_field){mLogger.debug("Package 2: pv_id " + pv_id + " pkg_name " + pkg_name + " pkg_version " + pkg_version + " v_ext "+ v_ext + " alias " + alias + " pkg_vcs_tag " + pkg_vcs_tag + " ripple_field " + ripple_field);mId = pv_id;mName = pkg_name;mVersion = pkg_version;int endindex = mVersion.length() - v_ext.length();if (endindex > 0){mVersion = mVersion.substring(0, endindex);}mExtension = v_ext;mAlias = alias;mVcsTag = pkg_vcs_tag;// setBuild is the defaultif (ripple_field == 'M'){mRippleField.setMajor();} else if (ripple_field == 'm'){mRippleField.setMinor();} else if (ripple_field == 'p'){mRippleField.setPatch();} else if (ripple_field == 'L'){mRippleField.setLimit();}}/*** constructor*/Package(){mLogger.debug("Package 3");mId = 0;mName = "null";mExtension = "null";mAlias = "null";mVcsTag = "null";}/*** constructor for test build purposes*/Package(String pkg_name, String v_ext, String alias, String pkg_vcs_tag, int testBuildInstruction, String email){mLogger.debug("Package 4: pkg_name " + pkg_name + " v_ext " + v_ext + " alias " + alias + " pkg_vcs_tag "+ pkg_vcs_tag);// don't need pv_idmId = -1;mName = pkg_name;// avoid interaction with real versionsmVersion = "0.0.0000";mExtension = v_ext;mAlias = alias;mTestBuildInstruction = testBuildInstruction;mTestBuildEmail = email;mTestBuildVcsTag = pkg_vcs_tag;}/*** constructor for unit test purposes*/public Package(ReleaseManager rm, String version, int majorLimit, int minorLimit, int patchLimit,int buildNumberLimit){mId = -1;mRippleField.setLimit();mVersion = version;mMajorLimit = majorLimit;mMinorLimit = minorLimit;mPatchLimit = patchLimit;mBuildLimit = buildNumberLimit;if (version.endsWith(".cots")){mExtension = ".cots";mVersion = version.substring(0, version.length() - 5);mChangeType.setMajor(false);mChangeType.setMinor(false);mChangeType.setPatch(true);mRippleField.setBuild();}try{mId = applyPV(rm, 0);} catch (Exception e){}}/*** accessor for unit test purposes*/public int getId(){return mId;}/*** accessor for unit test purposes*/public String getVersion(){return mVersion;}/*** returns true if mBuildStandardCollection is not empty*/boolean isReproducible(){mLogger.debug("isReproducible on Package " + mName);boolean retVal = false;if (mBuildStandardCollection.size() > 0){retVal = true;}mLogger.info("isReproducible returned " + retVal);return retVal;}/*** returns true if at least one of its BuildStandards has mWin32 or mGeneric* true*/boolean isWin32Built(){mLogger.debug("isWin32Built on Package " + mName);boolean retVal = false;for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();){BuildStandard buildStandard = it.next();if (buildStandard.getWin32() || buildStandard.getGeneric()){retVal = true;break;}}mLogger.info("isWin32Built returned " + retVal);return retVal;}/*** returns true if at least one of its BuildStandards has mSolaris or* mGeneric true*/boolean isSolarisBuilt(){mLogger.debug("isSolarisBuilt on Package " + mName);boolean retVal = false;for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();){BuildStandard buildStandard = it.next();if (buildStandard.getSolaris() || buildStandard.getGeneric()){retVal = true;break;}}mLogger.info("isSolarisBuilt returned " + retVal);return retVal;}/*** returns true if at least one of its BuildStandards has mLinux or mGeneric* true*/boolean isLinuxBuilt(){mLogger.debug("isLinuxBuilt on Package " + mName);boolean retVal = false;for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();){BuildStandard buildStandard = it.next();if (buildStandard.getLinux() || buildStandard.getGeneric()){retVal = true;break;}}mLogger.info("isLinuxBuilt returned " + retVal);return retVal;}/*** returns true if at least one of its BuildStandards has mGeneric true*/boolean isGeneric(){mLogger.debug("isGeneric on Package " + mName);boolean retVal = false;for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();){BuildStandard buildStandard = it.next();if (buildStandard.getGeneric()){retVal = true;break;}}mLogger.info("isGeneric returned " + retVal);return retVal;}/*** applies the required version number change returns 0 on success 1 on* cannot work with non standard versioning 2 on ripple field limitations* prevent a ripple build 3 on Invalid Change Type*/int applyPV(ReleaseManager releaseManager, int rtag_id) throws Exception{mLogger.debug("applyPV on Package " + mName);//// Four scenarios, only applyPV for 3 of them// mDirectlyPlanned mIndirectlyPlanned mArchivalExistence mForcedRipple// Action// WIP/test build exists: true true don't care don't care applyPV// Package version is out of date: false true true don't care applyPV// Forced ripple: false true don't care > 0 applyPV// Package version does not exist: false true false = 0 do not applyPV//if (!mDirectlyPlanned && mIndirectlyPlanned && !mArchivalExistence && mForcedRippleInstruction == 0){// the package has an mIndirectlyPlanned flag set true in daemon// mode because the package does not exist in an archive// do not apply a different package versionmLogger.info("applyPV !mDirectlyPlanned && mIndirectlyPlanned && !mArchivalExistence && zero mForcedRippleInstruction on Package "+ mName);releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);mLogger.info("applyPv returned 0");return 0;}// override - no longer doing a rebuild - version number change from// this point onif (mTestBuildInstruction == 0){mRequiresSourceControlInteraction = true;}//// Detect invalid change type// Flagged when package instance is created//if (mChangeType.mUnknown){mLogger.info("Package Vesrion specified on Package " + mName + "New Version:" + mVersion);mLogger.info("applyPv returned 3");return 3;}// If we are not calculating the new package version because the user// has fixed the version// of the package. We are given the new package version.if (mChangeType.mFixed){// mVersion is already setupmVersion = mFixedVersion;mLogger.info("Package Vesrion specified on Package " + mName + "New Version:" + mVersion);releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);mLogger.info("applyPv returned 0");return 0;}// We need to calculate the new version number//MutableInt major = new MutableInt();major.value = 0;MutableInt minor = new MutableInt();minor.value = 0;MutableInt patch = new MutableInt();patch.value = 1000;String field[] = mVersion.split("\\D");String nonStandardCotsVersion = "";if (field.length == 3){major.value = Integer.parseInt(field[0]);minor.value = Integer.parseInt(field[1]);patch.value = Integer.parseInt(field[2]);} else{//// Can ripple a .cots package under very controlled conditions// Its ends with a .patchBuild field// Package is marked as ripple via build number// Change type of Major and Minor are not allowed//if (!mChangeType.mMajor && !mChangeType.mMinor && mRippleField.mBuild && mExtension.compareTo(".cots") == 0&& field.length > 0){// DEVI 52782// allow and work with (ripple build) versions a.b.c.d....xxxx// where xxxx.length > 3String patchStr = field[field.length - 1];int patchLen = patchStr.length();// check patchStr is the last (at least 4) digitsif (patchLen > 3&& mVersion.substring(mVersion.length() - patchLen, mVersion.length()).compareTo(patchStr) == 0){patch.value = Integer.parseInt(patchStr);nonStandardCotsVersion = mVersion.substring(0, mVersion.length() - patchLen);}}if (nonStandardCotsVersion.length() == 0){// cannot work with non standard versioningmLogger.error("applyPV cannot work with non standard versioning");mLogger.info("applyPv returned 1");return 1;}}if (nonStandardCotsVersion.length() == 0 && patch.value < 1000 && field[2].substring(0, 1).compareTo("0") != 0){mLogger.info("applyPV accomodate old style mVersion of the form 1.0.1");patch.value = patch.value * 1000;}// mChangeType overrides mRippleFielddo{if (mChangeType.mMajor){if (!incrementFieldsAccordingToLimits(4, major, minor, patch)){mLogger.info("applyPv returned 2");return 2;}} else if (mChangeType.mMinor){if (!incrementFieldsAccordingToLimits(3, major, minor, patch)){mLogger.info("applyPv returned 2");return 2;}} else if (mChangeType.mPatch){if (!incrementFieldsAccordingToLimits(2, major, minor, patch)){mLogger.info("applyPv returned 2");return 2;}} else{if (mRippleField.mMajor){major.value++;mLogger.info("applyPV mRippleField.mMajor " + major.value);minor.value = 0;patch.value = 0;} else if (mRippleField.mMinor){minor.value++;mLogger.info("applyPV mRippleField.mMinor " + minor.value);patch.value = 0;} else if (mRippleField.mPatch){do{patch.value++;} while ((patch.value / 1000) * 1000 != patch.value);mLogger.info("applyPV mRippleField.mPatch " + patch.value);} else if (mRippleField.mBuild){patch.value++;mLogger.info("applyPV mRippleField.mBuild " + patch.value);} else{if (!incrementFieldsAccordingToLimits(1, major, minor, patch)){mLogger.info("applyPv returned 2");return 2;}}}if (nonStandardCotsVersion.length() == 0){mVersion = String.valueOf(major.value) + "." + String.valueOf(minor.value) + ".";} else{mVersion = nonStandardCotsVersion;}if (patch.value < 10){mVersion += "000";} else if (patch.value < 100){mVersion += "00";} else if (patch.value < 1000){mVersion += "0";}mVersion += String.valueOf(patch.value);} while (exists(releaseManager, rtag_id));releaseManager.claimVersion(mPid, mVersion + mExtension, rtag_id);mLogger.info("applyPv returned 0");return 0;}/*** increments fields according to mRippleField.mLimit if necessary will* apply it to the field passed as follows 1 = build 2 = patch 3 = minor* other = major returns true on success false on ripple field limitations* prevent a ripple build*/private boolean incrementFieldsAccordingToLimits(int field, MutableInt major, MutableInt minor, MutableInt patch){boolean retVal = true;if (!mChangeType.mLimit && !mRippleField.mLimit){// simple case// no need to take field limits into considerationswitch (field){case 1:// unreachable// the only scenario involving build number manipulation// involves the mRippleField.mLimit being setretVal = false;break;case 2:do{patch.value++;} while ((patch.value / 1000) * 1000 != patch.value);mLogger.info("incrementFieldsAccordingToLimits patch " + patch.value);break;case 3:minor.value++;mLogger.info("incrementFieldsAccordingToLimits minor " + minor.value);patch.value = 0;break;default:major.value++;mLogger.info("incrementFieldsAccordingToLimits major " + major.value);minor.value = 0;patch.value = 0;}} else{// take field limits into considerationboolean changeOccurred = false;boolean incrementField = true;switch (field){case 1:if (mBuildLimit != 0){// increment or reset the patch build numberint buildNumber = patch.value - (patch.value / 1000) * 1000;if (buildNumber < mBuildLimit){// can increment the patch build numberpatch.value++;mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit build number " + patch.value);changeOccurred = true;incrementField = false;} else{if (mPatchLimit == 0){// reset the patch number and patch build numberpatch.value = 0;}}}// no break by designcase 2:if (mPatchLimit != 0 && incrementField){// increment or reset the patch numberif ((patch.value / 1000) < mPatchLimit){do{patch.value++;} while ((patch.value / 1000) * 1000 != patch.value);mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit patch " + patch.value);changeOccurred = true;incrementField = false;} else{// reset the patch number and patch build numberpatch.value = 0;}}// no break by designcase 3:if (mMinorLimit != 0 && incrementField){// increment or reset the minor numberif (minor.value < mMinorLimit){minor.value++;patch.value = 0;mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit minor " + minor.value);changeOccurred = true;incrementField = false;} else{// reset the minor numberminor.value = 0;}}// no break by designdefault:if (mMajorLimit != 0 && incrementField){// increment or reset the major numberif (major.value < mMajorLimit){// increment the major numberchangeOccurred = true;major.value++;minor.value = 0;patch.value = 0;mLogger.info("incrementFieldsAccordingToLimits mRippleField.mLimit major " + major.value);}}}if (!changeOccurred){// unable to increment a field due to field limitationsmLogger.error("incrementFieldsAccordingToLimits ripple field limitations prevent a ripple build");mLogger.info("incrementFieldsAccordingToLimits returned false");retVal = false;}}return retVal;}/*** returns true if the version exists in the dpkg_archive or release manager* database claims the version in the release manager database*/private boolean exists(ReleaseManager releaseManager, int rtag_id) throws Exception{mLogger.debug("exists 1 on Package " + mName + " version " + mVersion + " extension " + mExtension);boolean retVal = false;if (!ReleaseManager.mUseDatabase){mLogger.info("exists 1 !releaseManager.mUseDatabase");} else{retVal = exists();if (!retVal){String pkg_version = new String(mVersion);if (mExtension.length() > 0){pkg_version += mExtension;}retVal = releaseManager.queryPackageVersions(mPid, pkg_version);}}mLogger.info("exists 1 returned " + retVal);return retVal;}/*** returns true if the required package archives (dpkg_archive) exist* attempt to recover from their transient loss*/public static boolean recover(){mLogger.debug("recover");boolean retVal = false;String Release = mGbeDpkg;if (Release != null){File dpkg = new File(mGbeDpkg);if (dpkg.exists()){retVal = true;mLogger.fatal("recover: dpkg_archive access has been restored");}}mLogger.info("recover returned " + retVal);return retVal;}/*** returns true if the version exists in a package archive (dpkg_archive)*/boolean exists() throws Exception{mLogger.debug("exists 2 on Package " + mName);boolean retVal = false;String Release = mGbeDpkg;if (Release == null){mLogger.fatal("exists 2 Release == null");throw new Exception("exists 2 Release == null");}File dpkg = new File(mGbeDpkg);if (!dpkg.exists()){mLogger.fatal("exists 2 " + mRecoverable);throw new Exception(mRecoverable);}String fs = System.getProperty("file.separator");String name = new String(Release);name += fs + mName + fs + mVersion + mExtension;File release = new File(name);if (release.exists()){mLogger.info("exists 2 release.exists()");retVal = true;}mArchivalExistence = retVal;mLogger.info("exists 2 returned " + retVal);return retVal;}/*** returns email information*/String emailInfo(String lf){String retVal = new String();for (Iterator<String> it = mBuildFailureEmailCollection.iterator(); it.hasNext();){String email = it.next();retVal += " <owner email=\"" + email + "\"/>" + lf;}return retVal;}/*** returns email information*/String emailInfoNonAntTask(){String retVal = null;for (Iterator<String> it = mBuildFailureEmailCollection.iterator(); it.hasNext();){String email = it.next();if (retVal == null){retVal = new String();} else{retVal += ",";}retVal += email;}return retVal;}/*** adds email to mBuildFailureEmailCollection if unique*/void addEmail(String email){boolean alreadyExists = false;for (Iterator<String> it = mBuildFailureEmailCollection.iterator(); it.hasNext();){String existingEmail = it.next();if (existingEmail.compareTo(email) == 0){alreadyExists = true;break;}}if (!alreadyExists){mBuildFailureEmailCollection.add(email);}}/*** accessor method*/void setEmail(){mBuildFailureEmailCollection.clear();addEmail(mTestBuildEmail);}/*** accessor method*/void setDependencyCollection(){// does not worry about mPackageDendencyCollection by designmDependencyCollection.clear();for (Iterator<String> it = mTestBuildDependencyCollection.iterator(); it.hasNext();){String dependency = it.next();mDependencyCollection.add(dependency);}}/*** accessor method*/void setBuildStandardCollection(){mBuildStandardCollection.clear();for (Iterator<BuildStandard> it = mTestBuildStandardCollection.iterator(); it.hasNext();){BuildStandard buildStandard = it.next();mBuildStandardCollection.add(buildStandard);}}/*** sends email notification and marks the instruction complete in the* database*/public void completeTestBuild(String mailServer, String mailSender, ReleaseManager releaseManager, String release,boolean success) throws SQLException, Exception{mLogger.debug("completeTestBuild");if (mTestBuildInstruction == 0){mLogger.fatal("completeTestBuild. Not Build Instruction");return;}String subject = (success == true ? "TEST BUILD COMPLETED SUCCESSFULLY" : "TEST BUILD FAILED") + " on package "+ mAlias;String mailBody = "Test build issues are identified in preceding build failure email.<p>" + "Release: "+ release + "<br>" + "Package: " + mAlias + "<br>" + "VcsTag: " + mVcsTag + "<br>"+ "Build dependencies:<br>";String indentString = " ";for (Iterator<Package> it3 = mPackageDependencyCollection.iterator(); it3.hasNext();){Package depend = it3.next();String dependsExtension = depend.mExtension;String dependsVersion = depend.mVersion;if (dependsExtension.length() > 0){dependsVersion += dependsExtension;}mailBody += indentString + "\'" + depend.mName + "\',\'" + dependsVersion + "\' <br>";}mailBody += "<br>Build standards:<br>";for (Iterator<BuildStandard> it = mBuildStandardCollection.iterator(); it.hasNext();){BuildStandard bs = it.next();String platform = bs.getPlatform(!ReleaseManager.mUseDatabase, false);if (platform.length() > 0){mailBody += indentString + platform + ", ";}String standard = bs.getBuildStandard(!ReleaseManager.mUseDatabase, false);if (standard.length() > 0){mailBody += standard + "<br>";}}mailBody += "<p><hr>";try{String target = emailInfoNonAntTask();mLogger.fatal("completeTestBuildEmail Server: " + mailServer);mLogger.fatal("completeTestBuildEmail Sender: " + mailSender);mLogger.fatal("completeTestBuildEmail Target: " + target);Smtpsend.send(mailServer, // mailServermailSender, // sourcetarget, // targetmailSender, // ccnull, // bccsubject, // subjectmailBody, // bodynull // attachment);} catch (Exception e){mLogger.warn("Email Failure: completeTestBuild:" + e.getMessage());}releaseManager.markDaemonInstCompletedConnect(mTestBuildInstruction);mLogger.fatal("completeTest. Returning");}/*** returns true if the package has a circular dependency*/public boolean hasCircularDependency(RippleEngine ripEng){mLogger.debug("hasCircularDependency");boolean retVal = detectCircularDependency(mAlias, ripEng);mLogger.info("hasCircularDependency returned " + retVal);return retVal;}/*** returns true if the package has a circular dependency*/public boolean detectCircularDependency(String alias, RippleEngine ripEng){mLogger.debug("detectCircularDependency");boolean retVal = false;// if this package has yet to be checked for circular dependencyif (!mCheckedCircularDependency){for (Iterator<String> it2 = mDependencyCollection.iterator(); it2.hasNext();){String dependencyAlias = it2.next();// check its direct dependencies for an alias matchif (alias.compareTo(dependencyAlias) == 0){retVal = true;break;}Package dependency = ripEng.findPackage(dependencyAlias);// check its indirect dependencies for an alias matchif (dependency.detectCircularDependency(alias, ripEng)){retVal = true;break;}}// mark the check completemCheckedCircularDependency = true;// persist the circular dependency outcomemHasCircularDependency = retVal;} else{// return the persisted circular dependency outcomeretVal = mHasCircularDependency;}mLogger.info("detectCircularDependency 2 returned " + retVal);return retVal;}/*** entity class supporting the ERG version numbering standard:* <major>.<minor>.<patch/build> patch/build is at least a 4 digit number* whose last 3 digits represent the build*/public class VersionNumberingStandard{/*** in terms of the mChangeType Package field, when true indicates the* contract of the package has changed in a non backwardly compatible* manner in terms of the mRippleField Package field, when true indicates* the major version number will be incremented** @attribute*/private boolean mMajor = false;/*** in terms of the mChangeType Package field, when true indicates the* contract of the package has changed in a backwardly compatible manner* in terms of the mRippleField Package field, when true indicates the* minor version number will be incremented** @attribute*/private boolean mMinor = false;/*** in terms of the mChangeType Package field, when true indicates the* contract of the package has not changed, but the package has changed* internally in terms of the mRippleField Package field, when true* indicates the minor version number will be incremented** @attribute*/private boolean mPatch = false;/*** in terms of the mChangeType Package field, when true indicates the* package has not changed, its dependencies potentially have in terms* of the mRippleField Package field, when true indicates the build* number will be incremented** @attribute*/private boolean mBuild = true;/*** in terms of the mChangeType Package field, when true indicates the* major, minor, and patch number will be incremented according to field* limits in terms of the mRippleField Package field, when true indicates* the major, minor, patch and build number will be incremented* according to field limits** @attribute*/private boolean mLimit = false;/*** in terms of the mChangeType Package field, when true indicates the* package version number will not be rippled. The user will have fixed* the version number. This is only application to WIP packages** @attribute*/private boolean mFixed = false;/*** in terms of the mChangeType Package field, when true indicates the* method of rippling a package version number is not known.** @attribute*/private boolean mUnknown = false;/*** constructor*/private VersionNumberingStandard(){mLogger.debug("VersionNumberingStandard");}/*** Reset all values to a known state**/void resetData(){mBuild = false;mMajor = false;mMinor = false;mPatch = false;mLimit = false;mFixed = false;mUnknown = false;}/*** sets mBuild true, mMajor false, mMinor false, mPatch false, mLimit* false*/void setBuild(){mLogger.debug("setBuild");resetData();mBuild = true;}/*** sets mBuild false, mMajor true, mMinor false, mPatch false, mLimit* false*/void setMajor(){mLogger.debug("setMajor");resetData();mMajor = true;}/*** sets mBuild false, mMajor true, mMinor false, mPatch false, mLimit* limit*/void setMajor(boolean limit){mLogger.debug("setMajor " + limit);resetData();mMajor = true;mLimit = limit;}/*** sets mBuild false, mMajor false, mMinor true, mPatch false, mLimit* false*/void setMinor(){mLogger.debug("setMinor");resetData();mMinor = true;}/*** sets mBuild false, mMajor false, mMinor true, mPatch false, mLimit* limit*/void setMinor(boolean limit){mLogger.debug("setMinor " + limit);resetData();mMinor = true;mLimit = limit;}/*** sets mBuild false, mMajor false, mMinor false, mPatch true, mLimit* false*/void setPatch(){mLogger.debug("setPatch");resetData();mPatch = true;}/*** sets mBuild false, mMajor false, mMinor false, mPatch true, mLimit* limit*/void setPatch(boolean limit){mLogger.debug("setPatch");resetData();mPatch = true;mLimit = limit;}/*** sets mBuild false, mMajor false, mMinor false, mPatch false, mLimit* true*/void setLimit(){mLogger.debug("setPatch");resetData();mLimit = true;}/*** sets parameters to indicate that the change type is Fixed. The* version number is set by the user and a ripple will not be calculated*/void setFixed(){mLogger.debug("setFixed");resetData();mFixed = true;}/*** Sets parameters to indicate that the change type is not known**/void setUnknown(){resetData();mUnknown = true;}}}