Subversion Repositories DevTools

Rev

Rev 4123 | Rev 4280 | Go to most recent revision | 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.ListIterator;
import java.util.Vector;
import java.lang.Exception;

import org.apache.log4j.Logger;

/**Plans release impact by generating a set of Strings containing build file content.
 */
public class RippleEngine
{
  /**collection of gbemachtypes in String form associated with the baseline
   * limited to the following items "win32", "sparc", "solaris10_sparc32", "solaris10_x86", "linux_i386"
   * accessed by Package::isLinuxBuilt, isSolarisBuilt, isWin32Built
   * @attribute
   */
  Vector<String> mGbeMachtypeCollection = new Vector<String>();
  
  /**configured mail server
   * @attribute
   */
  public String mMailServer = new String();

  /**configured mail sender user
   * @attribute
   */
  public String mMailSender = new String();

  /**configured global email target
   * @attribute
   */
  public String mGlobalTarget = new String();

  /**name associated with the baseline
   * @attribute
   */
  public String mBaselineName = new String();

  /**collection of released pv_ids associated with the release
   * @attribute
   */
  Vector<Integer> mReleasedPvIDCollection = new Vector<Integer>();

  /**timestamp associated with build file generation
   * @attribute
   */
  long mTimestamp = 0;

  /**set to "non generic", "generic" or "dummy" to indicate the nature of the package in the build file in daemon mode
   * @attribute
   */
  String mAddendum = new String("dummy");

  /**collection of build exceptions associated with the baseline
  /* used to determine (and report) what change in build exceptions happens as part of planRelease
   * deamon centric
   * @aggregation shared
   * @attribute
   */
  Vector<BuildExclusion> mBuildExclusionCollection = new Vector<BuildExclusion>();

  /**Logger
   * @attribute
   */
  private static final Logger mLogger = Logger.getLogger(RippleEngine.class);

  /**collection of escrow support file content in String form, set_up
   * @attribute
   */
  private Vector<String> mEscrowSupportCollection = new Vector<String>();

  /**package versions representing the baseline
   * escrow centric
   * @aggregation shared
   * @attribute
   */
  private Vector<Package> mPackageCollection = new Vector<Package>();

  /**index to current String item
   * @attribute
   */
  private int mBuildIndex;

  /**Database abstraction
   * @attribute
   */
  private ReleaseManager mReleaseManager;

  /**Baseline identifier (rtag_id for a release manager baseline, bom_id for deployment manager baseline)
   * @attribute
   */
  private int mBaseline;

  /**When true, mBuildCollection contains one item based on a release manager rtag_id and contains a daemon property
   * When false, mBuildCollection contains at least one item based on a deployment manager bom_id
   * Will be accessed by the Package class to calculate its mAlias
   * @attribute
   */
  boolean mDaemon;

  /**collection of build file content in String form
   * @attribute
   */
  private Vector<String> mBuildCollection = new Vector<String>();

  /**Warning message
   * @attribute
   */
  private static final String mAnyBuildPlatforms = new String("Warning. The following package versions are not reproducible on any build platform: ");

  /**Flag to control output to standard out
   * @attribute
   */
  private boolean mAnyBuildPlatformsFlag = true;

  /**Warning message
   * @attribute
   */
  private static final String mAssocBuildPlatforms = new String("Warning. The following package versions are not reproducible on the build platforms associated with this baseline: ");

  /**Flag to control output to standard out
   * @attribute
   */
  private boolean mAssocBuildPlatformsFlag = true;

  /**Warning message
   * @attribute
   */
  private static final String mNotInBaseline = new String("Warning. The following package versions are not reproducible as they are directly dependent upon package versions not in the baseline: ");

  /**Flag to control output to standard out
   * @attribute
   */
  private boolean mNotInBaselineFlag = true;

  /**Warning message
   * @attribute
   */
  private static final String mDependent = new String("Warning. The following package versions are not reproducible as they are directly/indirectly dependent upon not reproducible package versions: ");

  /**Flag to control output to standard out
   * @attribute
   */
  private boolean mDependentFlag = true;

  /**Warning message
   * @attribute
   */
  private static final String mCircularDependency = new String("Warning. The following package versions are not reproducible as they have circular dependencies: ");

  /**Flag to control output to standard out
   * @attribute
   */
  private boolean mCircularDependencyFlag = true;

  /**constructor
   */
  public RippleEngine(ReleaseManager releaseManager, int rtag_id, 
                      boolean isDaemon)
  {
    mLogger.debug("RippleEngine rtag_id " + rtag_id + " isDaemon " + isDaemon);
    mReleaseManager = releaseManager;
    mBaseline = rtag_id;
    mDaemon = isDaemon;
  }

  /**discards all build file content
   * plans new build file content
   */
  public void planRelease() throws SQLException, Exception
  {
    mLogger.warn("planRelease mDaemon " + mDaemon);
    boolean highProbabilityBuildRequirement = true;
    
    if ( mAddendum.compareTo("dummy") == 0 )
    {
      // the last planning session had no build requirement
      highProbabilityBuildRequirement = false;
    }
    
    mAddendum = "dummy";
    mBuildCollection.removeAllElements();
    mPackageCollection.removeAllElements();
    mReleasedPvIDCollection.removeAllElements();
    
    if ( !mDaemon )
    {
      mEscrowSupportCollection.removeAllElements();  
    }

    // use finally block in planRelease to ensure releaseMutex is called
    try
    {
      mReleaseManager.connectForPlanning(highProbabilityBuildRequirement);

      if ( mDaemon )
      {
        // claim the mutex
mLogger.warn("planRelease claimMutex");
        
        mReleaseManager.claimMutex();
        mBuildExclusionCollection.removeAllElements();
        Vector<BuildExclusion> tempBuildExclusionCollection = new Vector<BuildExclusion>();
        
mLogger.warn("planRelease queryBuildExclusions");
        mReleaseManager.queryBuildExclusions(tempBuildExclusionCollection, mBaseline);

        // only populate mBuildExclusionCollection with tempBuildExclusionCollection entries which have a relevant root_pv_id
        // ie the root_pv_id is ONLY relevant if it is null (-1) or it points to a pv_id in the collection
        // the package with a pv_id which is a root_pv_id may be removed ie when fixing a build issue
        for (Iterator<BuildExclusion> it = tempBuildExclusionCollection.iterator(); it.hasNext(); )
        {
          BuildExclusion buildExclusion = it.next();
          
          if ( buildExclusion.isRelevant(tempBuildExclusionCollection) )
          {
            mBuildExclusionCollection.add(buildExclusion);
          }
          else
          {
            // this is just a cosmetic step
            // it includes package versions which have been indirectly excluded
            // the build daemon ignores this information, but it serves to clarify this point to users
            buildExclusion.includeToBuild(mReleaseManager, mBaseline);
          }
        }
      }
      
mLogger.warn("planRelease queryPackageVersions");
      mReleaseManager.queryPackageVersions(this, mPackageCollection, mDaemon, mBaseline);
      
      // must deal with test builds here as they may impact upon package attributes
      // eg dependency collection and build standard differences
      // this gives test builds preferential treatment
      if ( mDaemon )
      {
        // process test builds
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
  
          if (p.mBuildFile == 0)
          {
            // package has yet to be processed
            if (  p.mTestBuildInstruction > 0 )
            {
              mLogger.info("planRelease package test build " + p.mName);

              // force patch for test build numbering
              p.mDirectlyPlanned = true;
              p.mChangeType.setPatch();
              p.mRequiresSourceControlInteraction = false;
              rippleIndirectlyPlanned(p);
              
              // put the mTestBuildAttributes to work
              p.mVcsTag = p.mTestBuildVcsTag;
              p.setEmail();
              p.setDependencyCollection();
              p.setBuildStandardCollection();
            }
          }
        }
      }
      
      // set up mPackageDependencyCollection
mLogger.warn("planRelease setup mPackageDependencyCollection");
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
         
        for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
        {
          String alias = it2.next();
          Package dependency = findPackage(alias);
          
          p.mPackageDependencyCollection.add(dependency);
        }
      }
      
      // DEVI 56479 detect and deal with circular dependencies
mLogger.warn("planRelease deal with circular dependencies");
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
         
        if ( p.hasCircularDependency( this ) )
        {
          mLogger.info("planRelease circular dependency detected " + p.mAlias);
          // exclude all dependent packages
          // max 50 chars
          rippleBuildExclude(p, p.mId, "Package has circular dependency", null, null);
           
          // take the package out of the build
          p.mBuildFile = -6;
          mLogger.info("planRelease set mBuildFile to -6 for package " + p.mAlias );
          standardOut(mCircularDependency, p.mAlias, mCircularDependencyFlag);
        }
      }

      // DEVI 55483 now use the fully built mPackageDependencyCollection (in rippleBuildExclude)
mLogger.warn("planRelease use the fully built mPackageDependencyCollection");
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
         
        for (Iterator<String> it2 = p.mDependencyCollection.iterator(); it2.hasNext(); )
        {
          String alias = it2.next();
          Package dependency = findPackage(alias);
          
          if (dependency == ReleaseManager.NULL_PACKAGE)
          {
            mLogger.info("planRelease dependency is not in the baseline " + alias);
            // exclude all dependent packages
            // max 50 chars
            rippleBuildExclude(p, p.mId, "Package build dependency not in the release", null, null);
             
            // take the package out of the build
            p.mBuildFile = -4;
            mLogger.info("planRelease set mBuildFile to -4 for package " + p.mAlias );
            standardOut(mNotInBaseline, p.mAlias, mNotInBaselineFlag);
            break;
          }
        }
      }

      // process packages which are not reproducible, and all packages dependent upon them      
mLogger.warn("planRelease process packages which are not reproducible");
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
  
        if (p.mBuildFile == 0)
        {
          // package has yet to be processed
          if (!p.isReproducible())
          {
            // for escrow build purposes, exclude all dependent package versions
            mLogger.info("planRelease package not reproducible " + p.mName);
            // max 50 chars
            rippleBuildExclude(p, p.mId, "Package has no build environment", null, null);
  
            // package is not reproducible, discard
            p.mBuildFile = -1;
            mLogger.info("planRelease set mBuildFile to -1 for package " + p.mAlias );
            standardOut(mAnyBuildPlatforms, p.mAlias, mAnyBuildPlatformsFlag);
          }
        }
      }
      
      // process packages which are not reproducible on the build platforms configured for this baseline
mLogger.warn("planRelease process packages which are not reproducible2");
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
         
        if (p.mBuildFile == 0)
        {
          // package has yet to be processed
          // assume it does not need to be reproduced for this baseline
          boolean reproduce = false;
           
          for (Iterator<String> it2 = mGbeMachtypeCollection.iterator(); it2.hasNext(); )
          {
            String machtype = it2.next();
            
            if ( machtype.compareTo("linux_i386") == 0 )
            {
              if ( p.isLinuxBuilt() )
              {
                reproduce = true;
                mLogger.info("planRelease package built on linux " + p.mAlias );
                break;
              }
            }
            else if ( machtype.compareTo("win32") == 0 )
            {
              if ( p.isWin32Built() )
              {
                reproduce = true;
                mLogger.info("planRelease package built on win32 " + p.mAlias );
                break;
              }
            }
            else if ( machtype.compareTo("sparc") == 0
                   || machtype.compareTo("solaris10_x86") == 0
                   || machtype.compareTo("solaris10_sparc32") == 0 )
            {
              if ( p.isSolarisBuilt() )
              {
                reproduce = true;
                mLogger.info("planRelease package built on solaris " + p.mAlias );
                break;
              }
            }
          }
  
          if ( !reproduce )
          {
            mLogger.info("planRelease package not reproducible on the build platforms configured for this baseline " + p.mName);
            
            if (mDaemon)
            {
              // DEVI 54816
              // for escrow build purposes, do not exclude all dependent package versions
              // max 50 chars
              rippleBuildExclude(p, p.mId, "Package not built for configured platforms", null, null);
            }
            
            // package is not reproducible on the build platforms configured for this baseline, discard
            p.mBuildFile = -2;
            mLogger.info("planRelease set mBuildFile to -2 for package " + p.mAlias );
            standardOut(mAssocBuildPlatforms, p.mAlias, mAssocBuildPlatformsFlag);
          }
        }
      }      
        
      if (mDaemon)
      {
        // process packages which are not ripple buildable, and all packages dependent upon them
mLogger.warn("planRelease process packages which are not ripple buildable");
        for (ListIterator<BuildExclusion> it = mBuildExclusionCollection.listIterator(); it.hasNext(); )
        {
          BuildExclusion be = it.next();
          
          for (Iterator<Package> it1 = mPackageCollection.iterator(); it1.hasNext(); )
          {
            Package p = it1.next();
            
            // ensure only root cause, non test build, build exclusions are excluded
            // mBuildExclusionCollection is at this point based on
            // relevant (direct and indirect) excluded pv's in the database
            if ( be.compare(p.mId) && be.isARootCause() && p.mTestBuildInstruction == 0 )
            {
              // package is not reproducible, discard
              rippleBuildExclude( p, p.mId, null, it, be );
              p.mBuildFile = -3;
              mLogger.info("planRelease set mBuildFile to -3 for package " + p.mAlias );
              break;
            }
          }
        }
        
        // process packages which need to be ripple built
mLogger.warn("planRelease process packages which need to be ripple built");
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
  
          if (p.mBuildFile == 0)
          {
            // package has yet to be processed
            if (p.mDirectlyPlanned)
            {
              // a WIP exists on the package
              // exclude all dependent package versions
              mLogger.info("planRelease package has WIP " + p.mName);
              rippleIndirectlyPlanned(p);
            }
            else
            {
              Iterator<Integer> it2 = p.mDependencyIDCollection.iterator();
              Iterator<Package> it3 = p.mPackageDependencyCollection.iterator();
              for ( ; it2.hasNext() && it3.hasNext(); )
              {
                Integer dpv_id = it2.next();
                Package dependency = it3.next();
  
                if ( !dependency.mAdvisoryRipple )
                {
                  // not advisory, ie has ripple build impact
                  boolean found = false;
                   
                  for ( Iterator<Integer> it4 = mReleasedPvIDCollection.iterator(); it4.hasNext(); )
                  {
                    Integer pv_id = it4.next();
  
                    if ( pv_id.compareTo(dpv_id) == 0 )
                    {
                      found = true;
                      break;
                    }
                  }
                   
                  if ( !found )
                  {
                    // the package is out of date
                    // exclude all dependent package versions
                    mLogger.info("planRelease package out of date " + p.mName);
                    rippleIndirectlyPlanned(p);                 
                    break;
                  }
                }
              }
            }
          }
        }
        
        // process packages which do not exist in the archive
mLogger.warn("planRelease process packages which do not exist in the archive");
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
  
          if (p.mBuildFile == 0)
          {
            // package has yet to be processed
            // for unit test purposes, assume all packages exist in the archive if released
            if ( ReleaseManager.mUseDatabase )
            {
              // only check existence outside the unit test
              if (!p.mDirectlyPlanned && !p.mIndirectlyPlanned)
              {
                // check package version archive existence
                if (!p.exists())
                {
                  mLogger.info("planRelease package not found in archive " + p.mName);
                  // DEVI 47395 the cause of this build is not WIP or ripple induced,
                  // it simply does not exist in the archive (has been removed)
                  // prevent source control interaction
                  p.mRequiresSourceControlInteraction = false;
                  rippleIndirectlyPlanned(p);
                }
              }
            }
          }
        }
        
        // process forced ripples
mLogger.warn("planRelease process forced ripples");
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
  
          if (p.mBuildFile == 0)
          {
            // package has yet to be processed
            if ( p.mForcedRippleInstruction > 0 )
            {
              mLogger.info("planRelease package forced ripple " + p.mName);
              rippleIndirectlyPlanned(p);
            }
          }
        }
      }
      else
      {
        // escrow reporting only     
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
    
          if (p.mBuildFile == -3)
          {
            standardOut(mDependent, p.mAlias, mDependentFlag);
          }
        }
      }
      
      // process remaining packages which need to be reproduced for this baseline
      // determine the build file for each package
      // for daemon builds, determine the first package that can be built now, this means the first package not dependent upon packages also to be built
      // set its mBuildNumber to 1, all remaining reproducible packages to 2
      // for escrow builds, determine the package versions that can be built in the build iteration
      // set their mBuildNumber to the build iteration
      // increment the build iteration and repeat until all package versions that need to be reproduced have been assigned a build iteration
      boolean allProcessed = false;
      int buildFile = 1;
  
      // delete the file <rtagId>official
      Integer rtag = new Integer(mBaseline);
      File rtagIdOfficial = new File(rtag + "official");
      
mLogger.warn("planRelease process Remaining-1");
      if (rtagIdOfficial.exists())
      {
        boolean del = rtagIdOfficial.delete();
        
        if ( !del )
        {
          // the delete failed
          // some literature suggests a forced garbage collection may free up resources associated with file handles
          // nothing to lose since the file "must" be deleted
          System.gc();
          del = rtagIdOfficial.delete();
            
          if ( !del )
          {
            mLogger.fatal("rtagIdOfficial.delete() returned " + del);
          }
        }
      }
      
      String raw_data = new String("");
      String lf = new String( System.getProperty("line.separator") );
  
mLogger.warn("planRelease process Remaining-2");
      do
      {
        boolean allDependenciesProcessed = true;
        
        do
        {
          // assume all dependencies have been processed
          allDependenciesProcessed = true;
          
          for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
          {
            Package p = it.next();
            
            if ( ( mDaemon && ( ( !p.mDirectlyPlanned && !p.mIndirectlyPlanned ) || p.mBuildFile < 0 ) ) ||
                 ( !mDaemon && p.mBuildFile == -2 ) )
            {
              // flag packages with no build requirement as processed in daemon mode
              // DEVI 54816 flag packages with a foreign build environment as processed in escrow mode
              p.mProcessed = true;
              mLogger.info("planRelease package has no build requirement " + p.mName);            
            }
            else if ( ( p.mBuildFile == 0 ) && ( (mDaemon && ( p.mDirectlyPlanned || p.mIndirectlyPlanned ) ) || ( !mDaemon ) ) )
            {
              // package yet to be processed and
              // in daemon mode has a build requirement or
              // in escrow mode
              boolean canBeBuiltNow = true;
              boolean allDependenciesForThisPackageProcessed = true;
              
              for ( Iterator<Package> it2 = p.mPackageDependencyCollection.iterator(); it2.hasNext(); )
              {
                Package dependency = it2.next();
                
                if ( !dependency.mProcessed )
                {
                  // cannot determine canBeBuiltNow until this dependency has been processed
                  allDependenciesForThisPackageProcessed = false;
                  allDependenciesProcessed = false;
                }
                else if ( ( mDaemon && ( dependency.mDirectlyPlanned ) || ( dependency.mIndirectlyPlanned ) ) || 
                          ( !mDaemon &&
                            ( ( dependency.mBuildFile == 0 ) ||
                              ( dependency.mBuildFile == buildFile &&
                                ( ( p.isLinuxBuilt() && !dependency.isLinuxBuilt() ) ||
                                  ( p.isWin32Built() && !dependency.isWin32Built() ) ||
                                  ( p.isSolarisBuilt() && !dependency.isSolarisBuilt() ) ||
                                  ( !p.isLinuxBuilt() && dependency.isLinuxBuilt() ) ||
                                  ( !p.isWin32Built() && dependency.isWin32Built() ) ||
                                  ( !p.isSolarisBuilt() && dependency.isSolarisBuilt() ) ) ) ) ) )
                {
                  // in daemon mode this processed dependency has a build requirement or
                  // in escrow mode...
                  // this processed dependency has not been assigned to a build iteration or
                  // this processed dependency has been assigned to this build iteration and does not build on this platform
                  canBeBuiltNow = false;
                  mLogger.info("planRelease package cannot be built in this iteration " + p.mName);
                  break;
                }
              }
              
              if (allDependenciesForThisPackageProcessed)
              {
                p.mProcessed = true;
                
                if ( mDaemon )
                {
                  if ( canBeBuiltNow )
                  {
                    // flag package with build requirement, may get downgraded to future build requirement
                    p.mBuildFile = 1;
                    mLogger.info("planRelease set mBuildFile to 1 for package " + p.mAlias );
                  }
                  else
                  {
                    // flag package with future build requirement
                    p.mBuildFile = 2;
                    mLogger.info("planRelease set mBuildFile to 2 for package " + p.mAlias );
                  }
                }
                else
                {
                  if ( canBeBuiltNow )
                  {
                    String isWin32Built = new String("");
                    
                    if ( p.isWin32Built() )
                    {
                      isWin32Built = "W";
                    }
                    
                    String isLinuxBuilt = new String("");
                    
                    if ( p.isLinuxBuilt() )
                    {
                      isLinuxBuilt = "L";
                    }
                    
                    String isSolarisBuilt = new String("");
                    
                    if ( p.isSolarisBuilt() )
                    {
                      isSolarisBuilt = "S";
                    }
                    
                    String isGeneric = new String("");
                    
                    if ( p.isGeneric() )
                    {
                      isGeneric = "G";
                    }
                    
                    raw_data += p.mAlias + "," +
                                isWin32Built + "," +
                                isLinuxBuilt + "," +
                                isSolarisBuilt + "," +
                                isGeneric + "," +
                                buildFile +
                                lf;
                    
                    // not daemon
                    p.mBuildFile = buildFile;
                    mLogger.info("planRelease set mBuildFile to " + buildFile + " for package " + p.mAlias );
                  }
                }
              }
            }
          }
        } while( !allDependenciesProcessed );
  
        if ( mDaemon )
        {
          for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
          {
            Package p = it.next();
            
            if ( p.mProcessed && p.mBuildFile == 1 )
            {
              p.mBuildFile = buildFile;
              mLogger.info("planRelease 2 set mBuildFile to " + buildFile + " for package " + p.mAlias );
                          
              if ( buildFile == 1 )
              {
                int pvApplied = p.applyPV(mReleaseManager, mBaseline);
                
                if ( pvApplied == 1 )
                {
                  // max 50 chars
                  rippleBuildExclude(p, p.mId, "Package has non standard versioning", null, null);
                }
                else if ( pvApplied == 2 )
                {
                  // max 50 chars
                  rippleBuildExclude(p, p.mId, "Package has reached ripple field limitations", null, null);
                }
                else if ( pvApplied == 3 )
                {
                  // max 50 chars
                  rippleBuildExclude(p, p.mId, "Package has invalid change type", null, null);
                }
                else
                {
                  buildFile = 2;
                  
                  if ( p.mForcedRippleInstruction > 0 )
                  {
                    mReleaseManager.markDaemonInstCompleted( p.mForcedRippleInstruction );
                  }
                  
                  if ( p.mTestBuildInstruction > 0 )
                  {
                    mReleaseManager.markDaemonInstInProgress( p.mTestBuildInstruction );
                  }
                }
              }
              else
              {
                mLogger.info("planRelease package has future (downgraded) build requirement " + p.mName + " " + buildFile);              
              }
            }
          }
        }
        
        // are more build files required
        allProcessed = true;
        
        if (mDaemon)
        {
          for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
          {
            Package p = it.next();
           
            if ( p.mBuildFile < 0 || ( !p.mDirectlyPlanned && !p.mIndirectlyPlanned ) )
            {
              // at this point...
              // only 1 package with a build requirement has a mBuildFile of 1,
              // all other packages with a build requirement have an mBuildFile of 2
              // give packages with no build requirement, reproducible or not, an mBuildFile of 3
              p.mBuildFile = 3;
              mLogger.info("planRelease 1 set mBuildFile to 3 for package " + p.mAlias );
            }
          }
        }
        else
        {
          // this is escrow mode centric
          for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
          {
            Package p = it.next();
           
            if ( p.mBuildFile == 0 )
            {
              // more build files are required
              allProcessed = false;
              mLogger.info("planRelease more build files are required for " + p.mName);
              break;
            }
          }
          
          buildFile++;
        }
      } while( !allProcessed );
      
      // persist the build files
      allProcessed = false;
      buildFile = 1;
mLogger.warn("planRelease process Remaining-3");
      
      if ( mDaemon )
      {
        // all interesting packages in daemon mode match the following filter
        buildFile = 3;
      }
  
      mTimestamp = System.currentTimeMillis();
  
      if ( !ReleaseManager.mUseDatabase )
      {
        mTimestamp = 123456789;
      }
  
      do
      {
        String buildFileContent = new String( generateBuildFileHeader() );
        
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
          
          // DEVI 54816
          // now set a packages mBuildFile to -2 in escrow mode, but do not ripple this through
          // its consumers need dependency package property info
          if ( ( ( p.mBuildFile > 0 ) && ( p.mBuildFile <= buildFile ) ) || ( !mDaemon && p.mBuildFile == -2 ) )
          {
            buildFileContent += generatePackageProperty(p);
          }
        }
        
        buildFileContent += generateTaskdef();
        
        String set_up = new String("");
        boolean daemonHasTarget = false;
        
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package p = it.next();
        
          if ( p.mBuildFile > 0 && p.mBuildFile <= buildFile )
          {
            buildFileContent += generateTarget(p, buildFile);
            
            if ( p.mBuildFile == 1 )
            {
              daemonHasTarget = true;
            }
          }
          
          if ( !mDaemon && buildFile == 1 )
          {
                  set_up += "jats jats_vcsrelease -extractfiles"
                      + " \"-label=" + p.mVcsTag + "\""
                      + " \"-view=" + p.mAlias + "\""
                      + " -root=. -noprefix"
                      + lf;
          }
        }
  
        if ( mDaemon && !daemonHasTarget )
        {
          // must have AbtSetUp, AbtTearDown, and AbtPublish targets
          buildFileContent += "<target name=\"AbtSetUp\"/>" + lf +
                              "<target name=\"AbtTearDown\"/>" + lf +
                              "<target name=\"AbtPublish\"/>" + lf;
        }
        
        if ( !mDaemon && buildFile == 1 )
        {
          mEscrowSupportCollection.add(set_up);
          mEscrowSupportCollection.add(raw_data);
        }
        
        buildFileContent += generateDefaultTarget( buildFile);
        buildFileContent += generateBuildFileFooter();
  
        mBuildCollection.add(buildFileContent);
        
        // are more build files required
        allProcessed = true;
        
        if (!mDaemon)
        {
          // this is escrow mode centric
          for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
          {
            Package p = it.next();
           
            if ( p.mBuildFile > buildFile )
            {
              // more build files are required
              allProcessed = false;
              mLogger.info("planRelease reiterating package has no build requirement " + p.mName + " " + p.mBuildFile + " " + buildFile);
              break;
            }
          } 
          
          buildFile++;
        }
      } while( !allProcessed );
    }
    finally
    {
mLogger.warn("planRelease finally");
      // this block is executed regardless of what happens in the try block
      // even if an exception is thrown
      // ensure the SELECT FOR UPDATE is released
      if ( mDaemon )
      {
        // attempt to release the SELECT FOR UPDATE through a commit
        // a commit must be done in the normal case
        // a commit may as well be done in the Exception case
        // in the case of a SQLException indicating database connectivity has been lost
        // having a go at the commit is superfluous
        // as the SELECT FOR UPDATE will have been released upon disconnection
        mReleaseManager.releaseMutex();
mLogger.warn("planRelease finally-1");
      }
      
      // ensure disconnect
      mReleaseManager.disconnectForPlanning(highProbabilityBuildRequirement);
mLogger.warn("planRelease finally-2");
    }

    mLogger.warn("planRelease mDaemon " + mDaemon + " returned");
  }

  /**reports what change in build exceptions happens as part of planRelease
   */
  public void reportChange() throws SQLException, Exception
  {
    for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
    {
      BuildExclusion buildExclusion = it.next();
      
      if ( !buildExclusion.isProcessed() )
      {
        // notify
        buildExclusion.excludeFromBuild(mReleaseManager, mBaseline);
        buildExclusion.email(mPackageCollection, mMailServer, mMailSender, mBaselineName, mReleaseManager);
      }
    }
  }
  
  /**returns first build file content
   * returns false if no build file content exists
   */
  public boolean getFirstBuildFileContent(MutableString content)
  {
    mLogger.debug("getFirstBuildFileContent");
    boolean retVal = true;
    
    try
    {
      mBuildIndex = 0;
      content.value = (String)mBuildCollection.get( mBuildIndex );
    }
    catch( ArrayIndexOutOfBoundsException e )
    {
      retVal = false;
    }
    
    mLogger.info("getFirstBuildFileContent returned " + retVal);
    return retVal;
  }

  /**returns next build file content
   * returns false if no next build file content exists
   */
  public boolean getNextBuildFileContent(MutableString content)
  {
    mLogger.debug("getNextBuildFileContent");
    boolean retVal = true;
    
    try
    {
      mBuildIndex++;
      content.value = (String)mBuildCollection.get( mBuildIndex );
    }
    catch( ArrayIndexOutOfBoundsException e )
    {
      retVal = false;
    }
    
    mLogger.debug("getNextBuildFileContent returned " + retVal);
    return retVal;
  }

  /**collects meta data associated with the baseline
   * this is sufficient to send an indefinite pause email notification
   */
  public void collectMetaData() throws SQLException, Exception
  {
    mLogger.debug("collectMetaData mDaemon " + mDaemon);
    mGbeMachtypeCollection.removeAllElements();
    
    try
    {
      mReleaseManager.connect();
      mReleaseManager.queryMachtypes(mGbeMachtypeCollection, mDaemon, mBaseline);
  
      if (mDaemon)
      {
        mMailServer = mReleaseManager.queryMailServer();
        mMailSender = mReleaseManager.queryMailSender();
        mGlobalTarget = mReleaseManager.queryGlobalAddresses();
      }
      mBaselineName = mReleaseManager.queryBaselineName(mDaemon, mBaseline);
    }
    finally
    {
      // this block is executed regardless of what happens in the try block
      // even if an exception is thrown
      // ensure disconnect
      mReleaseManager.disconnect();
    }
  }

  /**returns the Package with the matching mAlias or NULL_PACKAGE if no package has the mID
   */
  public Package findPackage(String alias)
  {
    mLogger.debug("findPackage");
    Package retVal = ReleaseManager.NULL_PACKAGE;

    for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
    {
      Package p = it.next();
      
      if ( p.mAlias.compareTo( alias ) == 0 )
      {
        retVal = p;
        break;
      }
    }
    
    mLogger.info("findPackage returned " + retVal.mName);
    return retVal;
  }

  /**sets the mBuildFile to -5 for the package and all dependent packages
   */
  private void rippleBuildExclude(Package p, int root_pv_id, String root_cause, ListIterator<BuildExclusion> list, BuildExclusion be )
  {
    mLogger.debug("rippleBuildExclude");
    if ( p.mBuildFile == 0 || p.mBuildFile == 1 )
    {
      p.mBuildFile = -5;
      mLogger.info("rippleBuildExclude set mBuildFile to -5 for package " + p.mAlias );
      
      if ( be != null )
      {
        be.process();
      }
      else
      {
        // if found, process it, else add it (unprocessed)
        boolean found = false;
        for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
        {
          BuildExclusion buildExclusion = it.next();
          
          if ( buildExclusion.compare(p.mId, root_pv_id, root_cause))
          {
            found = true;
            buildExclusion.process();
            break;
          }
        }
        
        if (!found)
        {
          // process all occurrences for this package
          // these will be superceded by a new build exclusion entry
          for (Iterator<BuildExclusion> it = mBuildExclusionCollection.iterator(); it.hasNext(); )
          {
            BuildExclusion buildExclusion = it.next();
            
            if ( buildExclusion.compare(p.mId))
            {
              buildExclusion.process();
            }
          }
          
          BuildExclusion buildExclusion = new BuildExclusion(p.mId, root_pv_id, root_cause, p.mTestBuildInstruction);
          
          if ( list == null )
          {
            mBuildExclusionCollection.add(buildExclusion);
          }
          else
          {
            // must use the ListIterator interface to add to the collection whilst iterating through it
            list.add(buildExclusion);
          }
        }
      }

      // only ripple a test build failure through for non test builds
      if ( p.mTestBuildInstruction == 0 )
      {
        // non test build
        for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
        {
          Package pkg = it.next();
          
          if ( pkg != p )
          {
            for (Iterator<Package> it2 = pkg.mPackageDependencyCollection.iterator(); it2.hasNext(); )
            {
              Package dependency = it2.next();
              
              if ( dependency == p )
              {
                rippleBuildExclude( pkg, root_pv_id, null, list, null );
                break;
              }
            }
          }
        }
      }
    }
    mLogger.info("rippleBuildExclude set " + p.mName + " " + p.mBuildFile);
  }

  public String escapeXml( String xml )
  {
    xml = xml.replaceAll("&", "&amp;");
    xml = xml.replaceAll("<", "&lt;");
    xml = xml.replaceAll(">", "&gt;");
    xml = xml.replaceAll("\"","&quot;");
    xml = xml.replaceAll("'", "&apos;");
    xml = xml.replaceAll("\\$", "\\$\\$");

    return xml;
  }

  /**returns a build file header for the mBaseline
   */
  private String generateBuildFileHeader()
  {
    mLogger.debug("generateBuildFileHeader");
    String lf = new String( System.getProperty("line.separator") );
    String retVal = new String("");
    retVal +=
    "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>" + lf +
    "<project name=\"mass\" default=\"full\" basedir=\".\">" + lf;
    
    if ( mDaemon )
    {
      retVal +=
      "<property name=\"abt_mail_server\" value=\"" + mMailServer + "\"/>" + lf +
      "<property name=\"abt_mail_sender\" value=\"" + mMailSender + "\"/>" + lf +
      "<property name=\"abt_rtag_id\" value=\"" + mBaseline + "\"/>" + lf +
      "<property name=\"abt_daemon\" value=\"" + mTimestamp + "\"/>" + lf;

      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
      
        if ( p.mBuildFile == 1 )
        {
          retVal +=
          "<property name=\"abt_package_name\" value=\"" + p.mName + "\"/>" + lf +
          "<property name=\"abt_package_version\" value=\"" + p.mVersion + p.mExtension + "\"/>" + lf +
          "<property name=\"abt_package_extension\" value=\"" + p.mExtension + "\"/>" + lf +
          loc(p, "abt_package_location", lf) +
          "<property name=\"abt_package_depends\" value=\"";

          // depends in the form 'cs','25.1.0000.cr';'Dinkumware_STL','1.0.0.cots'
          String depends = new String();
          
          for (Iterator<Package> it3 = p.mPackageDependencyCollection.iterator(); it3.hasNext(); )
          {
            Package depend = it3.next();
            
            if ( depends.compareTo( "" ) != 0 )
            {
              depends += ";";
            }
            depends += "\'" + depend.mName + "\'";
            depends += ",";
            String dependsExtension = depend.mExtension;
            String dependsVersion = depend.mVersion;
            
            if ( dependsExtension.length() > 0 )
            {
              dependsVersion += dependsExtension;
            }
            else
            {
              dependsExtension = ".";
            }
            depends += "\'" + dependsVersion + "\'";
          }
          
          retVal += depends + "\"/>" + lf +
          "<property name=\"abt_is_ripple\" value=\"";
          
          if ( p.mDirectlyPlanned )
          {
            retVal += "0";
          }
          else
          {
            retVal += "1";
          }
          
          retVal += "\"/>" + lf +
          "<property name=\"abt_package_version_id\" value=\"" + p.mId + "\"/>" + lf +
          "<property name=\"abt_does_not_require_source_control_interaction\" value=\"";
                          
          if ( ! p.mRequiresSourceControlInteraction )
          {
            retVal += "true";
          }
          else
          {
            retVal += "false";
          }
            
          retVal += "\"/>" + lf +
          "<property name=\"abt_test_build_instruction\" value=\"" + p.mTestBuildInstruction + "\"/>" + lf;
        }
      }
    }
    else
    {
      retVal +=
      "<property name=\"abt_rtag_id\" value=\"-1\"/>" + lf;
    }
    
    String majorVersionNumber = this.getClass().getPackage().getSpecificationVersion();
    
    if ( !ReleaseManager.mUseDatabase )
    {
        // hard code 11 for unit test purposes
         majorVersionNumber = "11";
    }
    
    retVal +=
    "<property name=\"abt_release\" value=\"" + escapeXml(mBaselineName) + "\"/>" + lf +
    "<property name=\"abt_buildtool_version\" value=\""+ majorVersionNumber + "\"/>" + lf +
    "<condition property=\"abt_family\" value=\"windows\">" + lf +
    "  <os family=\"windows\"/>" + lf +
    "</condition>" + lf +
    "<property name=\"abt_family\" value=\"unix\"/>" + lf;
    mLogger.info("generateBuildFileHeader returned " + retVal);
    return retVal;
  }

  /**returns an ant property for the passed Package
   */
  private String generatePackageProperty(Package p)
  {
    mLogger.debug("generatePackageProperty");
    String lf = new String( System.getProperty("line.separator") );
    String retVal = new String("");
    retVal +=
    "<property name=\"" + p.mAlias + "\" value=\"" + p.mName + " " + p.mVersion + p.mExtension + "\"/>" + lf;
    mLogger.info("generatePackageProperty returned " + retVal);
    return retVal;
  }

  /**returns an ant taskdef for the abt ant task
   */
  private String generateTaskdef()
  {
    mLogger.debug("generateTaskdef");
    String lf = new String( System.getProperty("line.separator") );
    String retVal = new String("");
    retVal +=
    "<taskdef name=\"abt\" classname=\"com.erggroup.buildtool.abt.ABT\"/>" + lf;
    return retVal;
  }

  /**returns an ant target for the passed Package
   * in daemon mode:
   *  packages are categorised with one of three mBuildFile values:
   *   1 the package to be built by this buildfile
   *   2 the packages with a future build requirement
   *   3 the packages with no build requirement
   *  the returned target depends on this categorisation and will have
   *   1 full abt info
   *   2 full dependency info to determine future build ordering but no abt info (will not build this package)
   *   3 only a name attribute (will not build this package)
   * in escrow mode:
   *  if the passed Package's mBuildFile is different (less than) the passed build file,
   *  the returned target have only a name attribute (will not build this package) 
   */
  private String generateTarget(Package p, int buildFile)
  {
    mLogger.debug("generateTarget");
    
    if ( ( mDaemon && p.mBuildFile == 1 ) || ( !mDaemon && !p.isGeneric() ) )
    {
      // populate 'missing' BuildStandards
      boolean solaris = false;
      boolean linux = false;
      boolean win32 = false;
      boolean jats = false;
      boolean determinedBuildStandard = false;
      
      for (Iterator<BuildStandard> it = p.mBuildStandardCollection.iterator(); it.hasNext(); )
      {
        BuildStandard bs = it.next();
        
        if ( bs.getSolaris() )
        {
          solaris = true;
        }
        else
        if ( bs.getLinux() )
        {
          linux = true;
        }
        else
        if ( bs.getWin32() )
        {
          win32 = true;
        }

        if ( !determinedBuildStandard && bs.getBuildStandard(!ReleaseManager.mUseDatabase, true).contains("<jats") )
        {
          jats = true;
          determinedBuildStandard = true;
        }
      }
      
      if ( !solaris )
      {
        BuildStandard bs = new BuildStandard(this);
        bs.setSolaris();
        
        if ( jats )
        {
          bs.setJatsNone();
        }
        else
        {
          bs.setAntNone();
        }
        
        p.mBuildStandardCollection.add(bs);
      }
      
      if ( !linux )
      {
        BuildStandard bs = new BuildStandard(this);
        bs.setLinux();
        
        if ( jats )
        {
          bs.setJatsNone();
        }
        else
        {
          bs.setAntNone();
        }
        
        p.mBuildStandardCollection.add(bs);
      }
      
      if ( !win32 )
      {
        BuildStandard bs = new BuildStandard(this);
        bs.setWin32();
        
        if ( jats )
        {
          bs.setJatsNone();
        }
        else
        {
          bs.setAntNone();
        }
        
        p.mBuildStandardCollection.add(bs);
      }
    }
    
    String lf = new String( System.getProperty("line.separator") );
    String retVal = new String("");
    
    if ( ( mDaemon && p.mBuildFile == 3 ) ||
         ( !mDaemon && ( p.mBuildFile < buildFile ) ) )
    {
      retVal +=
      "<target name=\"" + p.mAlias + "\"/>" + lf;
    }
    else
    {
      retVal +=
      "<target name=\"" + p.mAlias + ".wrap\"";
      
      if ( p.mPackageDependencyCollection.size() > 0 )
      {
        retVal +=" depends=\"";
        boolean comma = false;
        
        for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
        {
          Package dependency = it.next();
          // DEVI 54816
          if ( !mDaemon && dependency.mBuildFile == -2 )
          {
            // ignore targets which build in foreign environments in escrow mode
            continue;
          }
          if (comma)
          {
            retVal += ",";
          }
          comma = true;
          
          retVal += dependency.mAlias;
        }
        
        retVal += "\"";
      }
      retVal += ">" + lf;

      if ( !mDaemon )
      {
        boolean hasDependenciesBuiltInThisIteration = false;
        if ( ( p.mPackageDependencyCollection.size() > 0 ) )
        {
          for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
          {
            Package dependency = it.next();
            
            if ( dependency.mBuildFile == buildFile )
            {
              hasDependenciesBuiltInThisIteration = true;
              break;
            }
          }
        }
        
        if ( hasDependenciesBuiltInThisIteration )
        {
          retVal +=
          "  <condition property=\"" + p.mAlias + ".build\">" + lf +
          "    <and>" + lf;
          
          for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
          {
            Package dependency = it.next();
            
            if ( dependency.mBuildFile == buildFile )
            {
              retVal +=
              "      <or>" + lf +
              "        <equals arg1=\"${" + dependency.mAlias + ".res}\" arg2=\"0\"/>" + lf +
              "        <equals arg1=\"${" + dependency.mAlias + ".res}\" arg2=\"257\"/>" + lf +
              "      </or>" + lf;
            }
          }
          
          retVal +=
          "    </and>" + lf +
          "  </condition>" + lf;
        }
        else
        {
          retVal += "  <property name=\"" + p.mAlias + ".build\" value=\"\"/>" + lf;
        }
      }
      
      retVal +=
      "</target>" + lf +
      "<target name=\"" + p.mAlias + "\" depends=\"" + p.mAlias + ".wrap\"";
      
      if ( !mDaemon )
      {
        retVal += " if=\"" + p.mAlias + ".build\"";
      }
      
      retVal += ">" + lf;
      
      if ( mDaemon && p.mBuildFile == 1 )
      {
        retVal +=
        "<property name=\"" + p.mAlias + "pkg_id\" value=\"" + p.mPid + "\"/>" + lf +
        "<property name=\"" + p.mAlias + "pv_id\" value=\"" + p.mId + "\"/>" + lf;
      }
      
      if ( ( mDaemon && p.mBuildFile == 1 ) || !mDaemon )
      {
        retVal +=
        "<property name=\"" + p.mAlias + "packagename\" value=\"" + p.mName + "\"/>" + lf +
        "<property name=\"" + p.mAlias + "packageversion\" value=\"" + p.mVersion + "\"/>" + lf +
        "<property name=\"" + p.mAlias + "packageextension\" value=\"";
        
        if ( p.mExtension.length() > 0 )
        {
          // drop the .
          retVal += p.mExtension.substring(1);
        }
        else
        {
          retVal += p.mExtension;
        }
        
        retVal += "\"/>" + lf +
        "<property name=\"" + p.mAlias + "packagevcstag\" value=\"" + p.mVcsTag + "\"/>" + lf;
        
        if ( p.mDirectlyPlanned )
        {
          retVal += "<property name=\"" + p.mAlias + "directchange\" value=\"\"/>" + lf;
        }
        
        if ( ! p.mRequiresSourceControlInteraction )
        {
          retVal += "<property name=\"" + p.mAlias + "doesnotrequiresourcecontrolinteraction\" value=\"\"/>" + lf;
        }
        
        mAddendum = "non generic";
  
        if ( p.isGeneric() )
        {
          mAddendum = "generic";
          retVal += "<property name=\"" + p.mAlias + "generic\" value=\"\"/>" + lf;
        }
  
        retVal += loc(p, p.mAlias + "loc", lf);
        
        if ( p.mHasAutomatedUnitTests && mDaemon )
        {
          retVal += 
          "<property name=\"" + p.mAlias + "unittests\" value=\"\"/>" + lf;
        }
      }
      
      retVal += "<abt>" + lf;
      
      if ( ( mDaemon && p.mBuildFile == 1 ) || !mDaemon )
      {
        for (Iterator<Package> it = p.mPackageDependencyCollection.iterator(); it.hasNext(); )
        {
          Package dependency = it.next();
          retVal +=
          "  <depend package_alias=\"${" + dependency.mAlias + "}\"/>" + lf;
        }

        retVal += buildInfo(p, lf, false);
      }
      
      if ( mDaemon && p.mBuildFile == 1 )
      {
        retVal += p.emailInfo( lf );
      }
      
      retVal += "</abt>" + lf +
      "</target>" + lf;
      
      if ( mDaemon && p.mBuildFile == 1 )
      {
        retVal +=
        "<target name=\"AbtSetUp\">" + lf +
        "<property name=\"AbtSetUppackagevcstag\" value=\"" + p.mVcsTag + "\"/>" + lf +
        "<property name=\"AbtSetUppackagename\" value=\"" + p.mName + "\"/>" + lf;

        retVal +=
        "<abt>" + lf +
        p.emailInfo( lf ) +
        "</abt>" + lf +
        "</target>" + lf;

        retVal +=
        "<target name=\"AbtTearDown\">" + lf +
        "<property name=\"AbtTearDownpackagevcstag\" value=\"" + p.mVcsTag + "\"/>" + lf +
        "<property name=\"AbtTearDownpackagename\" value=\"" + p.mName + "\"/>" + lf +
        "<property name=\"AbtTearDownpackageversion\" value=\"" + p.mVersion + "\"/>" + lf +
        "<property name=\"AbtTearDownpackageextension\" value=\"";
        
        if ( p.mExtension.length() > 0 )
        {
          // drop the .
          retVal += p.mExtension.substring(1);
        }
        else
        {
          retVal += p.mExtension;
        }
        
        retVal += "\"/>" + lf;

        if ( p.isGeneric() )
        {
          retVal += "<property name=\"" + p.mAlias + "generic\" value=\"\"/>" + lf;
        }

        retVal +=        
        "<abt>" + lf +
        buildInfo(p, lf, false) +
        p.emailInfo( lf ) +
        "</abt>" + lf +
        "</target>" + lf +
        "<target name=\"AbtPublish\">" + lf +
        "<property name=\"AbtPublishpackagevcstag\" value=\"" + p.mVcsTag + "\"/>" + lf +
        "<property name=\"AbtPublishpackagename\" value=\"" + p.mName + "\"/>" + lf +
        "<property name=\"AbtPublishpackageversion\" value=\"" + p.mVersion + "\"/>" + lf +
        "<property name=\"AbtPublishpackageextension\" value=\"";
        
        if ( p.mExtension.length() > 0 )
        {
          // drop the .
          retVal += p.mExtension.substring(1);
        }
        else
        {
          retVal += p.mExtension;
        }
        
        retVal += "\"/>" + lf;
        
        if ( p.mDirectlyPlanned )
        {
          retVal += "<property name=\"AbtPublishdirectchange\" value=\"\"/>" + lf;
        }
        
        if ( ! p.mRequiresSourceControlInteraction )
        {
          retVal += "<property name=\"AbtPublishdoesnotrequiresourcecontrolinteraction\" value=\"\"/>" + lf;
        }
        
        if ( p.isGeneric() )
        {
          retVal += "<property name=\"AbtPublishgeneric\" value=\"\"/>" + lf;
        }

        retVal += loc(p, "AbtPublishloc", lf);
        retVal +=
        "<abt>" + lf +
        buildInfo(p, lf, true) +
        p.emailInfo( lf ) +
        "</abt>" + lf +
        "</target>" + lf;
      }
    }
    mLogger.info("generateTarget returned " + retVal);
    return retVal;
  }

  /**returns an ant default target for the current build iteration
   */
  private String generateDefaultTarget(int buildFile)
  {
    mLogger.debug("generateDefaultTarget");
    String lf = new String( System.getProperty("line.separator") );
    String retVal = new String("");
    retVal +=
    "<target name=\"fullstart\">" + lf;
    
    if (buildFile == 1)
    {
      retVal +=
      "<echo message=\"${line.separator}" + mAnyBuildPlatforms + "${line.separator}${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
      
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
        
        if ( p.mBuildFile == -1 )
        {
          retVal +=
          "<echo message=\"${line.separator}" + p.mAlias + "${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
        }
      }

      retVal +=
      "<echo message=\"${line.separator}" + mAssocBuildPlatforms + "${line.separator}${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
      
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
        
        if ( p.mBuildFile == -2 )
        {
          retVal +=
          "<echo message=\"${line.separator}" + p.mAlias + "${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
        }
      }

      retVal +=
      "<echo message=\"${line.separator}" + mNotInBaseline + "${line.separator}${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
      
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
        
        if ( p.mBuildFile == -4 )
        {
          retVal +=
          "<echo message=\"${line.separator}" + p.mAlias + "${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
        }
      }

      retVal +=
      "<echo message=\"${line.separator}" + mDependent + "${line.separator}${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
      
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package p = it.next();
        
        if ( p.mBuildFile == -5 )
        {
          retVal +=
          "<echo message=\"${line.separator}" + p.mAlias + "${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
        }
      }
    }
    if ( !mDaemon )
    {
      retVal +=
      "<echo message=\"${line.separator}Build Started:${line.separator}${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
    }
    
    retVal +=
    "</target>" + lf +
    "<target name=\"full\" depends=\"fullstart";
    
    for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
    {
      Package p = it.next();
      
      if ( ( p.mBuildFile > 0 ) && ( p.mBuildFile <= buildFile ) )
      {
        retVal += "," + p.mAlias;
      }
    }
    
    retVal +=
    "\">" + lf;
    
    if ( !mDaemon )
    {
      retVal +=
      "<echo message=\"${line.separator}Build Finished${line.separator}\" file=\"publish.log\" append=\"true\"/>" + lf;
    }
    
    retVal +=
    "</target>" + lf;
    return retVal;
  }

  /**returns a build file footer
   */
  private String generateBuildFileFooter()
  {
    mLogger.debug("generateBuildFileFooter");
    String retVal = new String("</project>");
    return retVal;
  }

  /**sets the mIndirectlyPlanned true for the package and all dependent packages
   */
  private void rippleIndirectlyPlanned(Package p)
  {
    mLogger.debug("rippleIndirectlyPlanned");
    if ( !p.mIndirectlyPlanned && p.mBuildFile == 0 )
    {
      p.mIndirectlyPlanned = true;
      
      for (Iterator<Package> it = mPackageCollection.iterator(); it.hasNext(); )
      {
        Package pkg = it.next();
        
        if ( pkg != p )
        {
          for (Iterator<Package> it2 = pkg.mPackageDependencyCollection.iterator(); it2.hasNext(); )
          {
            Package dependency = it2.next();
            
            if ( dependency == p )
            {
              rippleIndirectlyPlanned( pkg );
              break;
            }
          }
        }
      }
    }
    mLogger.info("rippleIndirectlyPlanned set " + p.mName + " " + p.mIndirectlyPlanned);    
  }

  /**accessor method
   */
  public String getESCROWSetUp()
  {
    mLogger.debug("getESCROWSetUp");
    String retVal = new String("");
    
    try
    {
      if ( mEscrowSupportCollection.size() >= 1 )
      {
        retVal = (String)mEscrowSupportCollection.get(0);
      }
    }
    catch( ArrayIndexOutOfBoundsException e )
    {
    }
    
    mLogger.info("getESCROWSetUp returned " + retVal);
    return retVal;
  }

  /**accessor method
   */
  public String getRawData()
  {
    mLogger.debug("getRawData");
    String retVal = new String("");
    
    try
    {
      if ( mEscrowSupportCollection.size() >= 2 )
      {
        retVal = (String)mEscrowSupportCollection.get(1);
      }
    }
    catch( ArrayIndexOutOfBoundsException e )
    {
    }
    
    mLogger.info("getRawData returned " + retVal);
    return retVal;
  }

  /**returns first build file content and addendum
   * the addendum value is one of "non generic", "generic" or "dummy"
   */
  public void getFirstBuildFileContent(MutableString content, 
                                MutableString addendum)
  {
    mLogger.debug("getFirstBuildFileContent");
    try
    {
      mBuildIndex = 0;
      content.value = (String)mBuildCollection.get( mBuildIndex );
      addendum.value = mAddendum;
    }
    catch( ArrayIndexOutOfBoundsException e )
    {
    }
    mLogger.info("getFirstBuildFileContent passed " + content.value + addendum.value);
  }

  /**returns the build loc
   */
  private String loc(Package p, String target, String lf)
  {
    mLogger.debug("loc");
    String retVal = new String();
    String loc = new String("/");

    if (mDaemon)
    {
      // Daemon: Start in root of view/workspace
      loc += mBaseline;
    }
    else
    {
      // mAlias used with jats -extractfiles -view
      loc += p.mAlias;
    }

    //
    //  Always use '/' as a path seperator - even if user has specified '\'
    //  Ant can handle it.
    //
    loc = loc.replace('\\', '/');
    retVal += 
    "<property name=\"" + target + "\" value=\"" + loc + "\"/>" + lf;

    mLogger.info("loc returned " + retVal);
    return retVal;
  }

  /**returns the buildInfo
   */
  private String buildInfo(Package p, String lf, boolean filter)
  {
    mLogger.debug("buildInfo");

    String platforms = new String();
    String standards = new String();
    
    for (Iterator<BuildStandard> it = p.mBuildStandardCollection.iterator(); it.hasNext(); )
    {
      BuildStandard bs = it.next();
      
      if ( !filter )
      {
        String platform = bs.getPlatform(!ReleaseManager.mUseDatabase, true);
      
        if ( platform.length() > 0 )
        {
          platforms += platform + lf;
        }

        String standard = bs.getBuildStandard(!ReleaseManager.mUseDatabase, true);
        
        if ( standard.length() > 0 )
        {
          standards += standard + lf;
        }
      }
      else
      {
        if ( !bs.getBuildStandard(!ReleaseManager.mUseDatabase, true).contains("\"none\"") )
        {
          String platform = bs.getPlatform(!ReleaseManager.mUseDatabase, true);
          
          if ( platform.length() > 0 )
          {
            platforms += platform + lf;
          }
          
          String standard = bs.getBuildStandard(!ReleaseManager.mUseDatabase, true);
          
          if ( standard.length() > 0 )
          {
            standards += standard + lf;
          }
        }
      }
    }
    
    mLogger.info("buildInfo returned " + platforms + standards);
    return platforms + standards;
  }

  /**prints to standard out in escrow mode only
   */
  private void standardOut(final String message, final String alias, boolean printMessage)
  {
    mLogger.debug("standardOut");
    if (!mDaemon)
    {
      if ( printMessage )
      {
        System.out.println(message);
        // switch the message off
        printMessage = false;
      }
      
      System.out.println(alias);
    }
  }
}