Subversion Repositories DevTools

Rev

Rev 7333 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6914 dpurdie 1
package com.erggroup.buildtool.ripple;
2
 
3
import java.sql.Array;
4
import java.sql.CallableStatement;
5
import java.sql.Clob;
6
import java.sql.Connection;
7
import java.sql.DriverManager;
8
import java.sql.PreparedStatement;
9
import java.sql.ResultSet;
10
import java.sql.SQLException;
11
import java.sql.Timestamp;
12
import java.sql.Types;
13
import java.util.ArrayList;
14
import java.util.Arrays;
15
import java.util.Calendar;
16
import java.util.Date;
17
import java.util.GregorianCalendar;
18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
import java.util.concurrent.locks.ReentrantLock;
22
 
23
import oracle.sql.ArrayDescriptor;
24
 
7033 dpurdie 25
import org.slf4j.Logger;
26
import org.slf4j.LoggerFactory;
6914 dpurdie 27
 
7333 dpurdie 28
import com.erggroup.buildtool.daemon.BuildInfo;
6914 dpurdie 29
import com.erggroup.buildtool.ripple.RunLevel.BuildState;
30
import com.erggroup.buildtool.utilities.MutableDate;
7333 dpurdie 31
import com.erggroup.buildtool.utilities.StringAppender;
6914 dpurdie 32
 
33
/**Release Manager schema abstraction
34
 */
35
public class ReleaseManager implements Cloneable
36
{
37
    /**Unit test hook.
38
     * Prevents Oracle interaction when false.
39
     * @attribute
40
     */
7046 dpurdie 41
    public boolean mUseDatabase = true;
6914 dpurdie 42
 
43
    /**Debug Support.
44
     * Set to false if EnvVar GBE_BUILDTOOL_DEBUG exists
45
     * Value of GBE_BUILDTOOL_DEBUG is expected to be an email if greater than
46
     * one character.
47
     *
48
     * When set to false will:
49
     *    Prevents use of Oracle Mutex and potential lockout during debug sessions.
50
     *    Prevent the initiation of an indefinite pause.
51
     *    Force abt_usetestarchive, Add -testArchive to the assemble_dpkg command
52
     * @attribute
53
     */
54
    private static boolean mUseMutex = true;
55
 
56
    /** 
57
     * Reasons for building a package
58
     * The character code is inserted directly into the Release Manager Database
59
     * 
60
     */
61
    public enum BuildReason {
62
 
7099 dpurdie 63
        Ripple('R'),            // Caused by mismatched dependencies
64
        Test('T'),              // A test request via a daemon instruction
65
        NewVersion('N'),        // A user WIP will create a new version of a package
66
        Restore('P'),           // Package not present in dpkg_archive and must be rebuilt
67
        Forced('F');            // Forced Ripple Request via a daemon instruction
6914 dpurdie 68
 
69
        private char reason;
70
        private BuildReason(char reason) { this.reason = reason; }
71
        @Override
72
        public  String toString() { return String.valueOf(reason); }
73
        public static BuildReason fromValue(String value) {  
74
            if (value != null) {  
75
              for (BuildReason vReason : values()) {  
76
                if (vReason.reason == value.charAt(0) ) {  
77
                  return vReason;  
78
                }  
79
              }  
80
            }
81
            return null;  
82
        }
83
    }
84
 
85
    /**
86
     * The build result : Error, Complete ...
87
     * The character code is inserted directly into the Release Manager Database
88
     */
89
    public enum BuildResult {
90
 
91
        Building('B'),
92
        BuildError('E'),
93
        Complete('C'),
94
        SystemError('S');
95
 
96
        private char state;
97
        private BuildResult(char state) { this.state = state; }
98
        @Override
99
        public  String toString() { return String.valueOf(state); }
100
//        public static BuildResult fromValue(String value) {  
101
//            if (value != null) {  
102
//              for (BuildResult vState : values()) {  
103
//                if (vState.state == value.charAt(0) ) {  
104
//                  return vState;  
105
//                }  
106
//              }  
107
//            }
108
//            return null;  
109
//        }
110
    }
111
 
112
    /**package object of no consequence
113
     * @attribute
114
     */
115
    public static final Package NULL_PACKAGE = new Package();
116
 
117
    /**Logger
118
     * @attribute
119
     */
7033 dpurdie 120
    private static final Logger mLogger = LoggerFactory.getLogger(ReleaseManager.class);
6914 dpurdie 121
 
122
    /** Class to contain a lock and a connection as a single entity
123
     * 
124
     */
125
    static class RmConnection {
126
    	/**
127
    	 *  Connection to the database
128
    	 */
129
    	public Connection mConnection = null;
130
 
131
    	/**
132
    	 *  Lock used to control access to the connection
133
    	 */
134
    	public final ReentrantLock mSession = new ReentrantLock();
135
 
136
    	/** 
137
    	 * Close the connection on disconnect
138
    	 */
139
    	public boolean mCloseOnDisconnect = false;
140
 
141
    	public RmConnection ( boolean closeMe)
142
    	{
143
    		mCloseOnDisconnect = closeMe;
144
    	}
145
 
146
    	/**
147
    	 *  Close the connection - do not throw an error
148
    	 */
149
    	void closeConnection()
150
    	{
151
    		closeConnection(mConnection);
152
    	}
153
 
154
    	/**
155
    	 *  Close the specified connection - do not throw an error.
156
    	 *  To be used for general error handling
157
    	 * @param connection
158
    	 */
159
    	static void closeConnection( Connection connection )
160
    	{
161
            try {
162
                if (connection != null)
163
                	connection.close();
164
            }
165
            catch (SQLException e)
166
            {
7044 dpurdie 167
                mLogger.error("SQL Exception closing connection: {}", e.getMessage());
6914 dpurdie 168
            }
169
    	}
170
    }
171
 
172
    /**database connection for use when not planning a build
173
     * @attribute
174
     */
175
    private static RmConnection mNonPlanningConnection = new RmConnection(false);
176
 
177
    /**database session handle for use when planning a build
178
     * @attribute
179
     */
180
    private static RmConnection mPlanningConnection = new RmConnection(true);
181
 
182
    /**database session handle
183
     * note this handle is only ever set to mNonPlanningConnection or mPlanningConnection
184
     * @attribute
185
     */
186
    private Connection mConnection = null;
187
    private boolean    mIsConnected = false;
188
 
189
    /**thread synchronization governing database connection request queuing
190
     * this lock is used by master threads with a low priority planning requirement
191
     * use the fairness parameter to grant access to the longest waiting thread
192
     * @attribute
193
     */
194
    private static final ReentrantLock mLowPriorityQueue = new ReentrantLock(true);
195
 
196
    /**collection of ReleaseConfig objects
197
     * @attribute
198
     */
199
    public ReleaseConfigData mReleaseConfigCollection = new ReleaseConfigData();
200
 
201
    /**database connection string
202
     * @attribute
203
     */
204
    public String mConnectionString = "";
205
 
206
    /**database username
207
     * @attribute
208
     */
209
    private String mUsername = "";
210
 
211
    /**database password
212
     * @attribute
213
     */
214
    private String mPassword = "";
215
 
216
    /**collection of RunLevel objects
217
     * @attribute
218
     */
219
    public List<RunLevelData> mRunLevelCollection = new ArrayList<RunLevelData>();
220
 
221
    /**set in claimVersion, cleared in discardVersion
222
     * @attribute
223
     */
224
    private String mPlannedPkgId = null;
225
 
226
    /**set in claimVersion, cleared in discardVersion
227
     * @attribute
228
     */
229
 
230
    private String mPlannedPkgVersion = null;
231
 
232
    /**prevents inadvertently attempting a commit which releases record locks in between claimMutex and releaseMutex
233
     * @attribute
234
     */
235
    private boolean mDoNotCommit = false;
236
 
237
     /**
238
     * Controls the data collection mode.
239
     * True : daemon Mode (default)
240
     * False: escrow Mode
241
     */
242
    public boolean mDaemon = true;
243
 
244
    /**
245
     * Indication of the state of the RM mutex
246
     * Used only for reporting
247
     */
248
    public String mMutexState = "";
249
 
250
    /**
251
     *  The number of seconds to postpone a shut down of a daemon set
252
     *  after the thread has started. 
253
     *  
254
     *  This will prevent a daemon from being automatically disabled as soon
255
     *  as it is restarted
256
     *  
257
     *  Set to four hours
258
     */
259
    private static final long mPostponeShutdown = 4L * 60L * 60L;
260
 
261
 
262
    /**constructor
263
     * @param connectionString
264
     * @param username
265
     * @param password
266
     */
267
    public ReleaseManager(final String connectionString, final String username, final String password)
268
    {
7044 dpurdie 269
        mLogger.debug("ReleaseManager {}", connectionString);
6914 dpurdie 270
        mConnectionString = connectionString;
271
        mUsername = username;
272
        mPassword = password;
273
 
274
        String gbeBtDebug = System.getenv("GBE_BUILDTOOL_DEBUG");
275
        if ( gbeBtDebug != null )
276
        {
7033 dpurdie 277
            mLogger.error("GBE_BUILDTOOL_DEBUG set - Use of database mutex supressed");
6914 dpurdie 278
            setNoMutex();
279
        }
280
    }
281
 
282
    /**
283
     * Clone an instance of this class
284
     */
285
    @Override
286
    public Object clone() throws CloneNotSupportedException {
287
 
288
        //  Clone myself - using Java's build in stuff
289
        ReleaseManager clonedObj = (ReleaseManager) super.clone();
290
 
291
        //  Fix up several members
292
        //
293
        clonedObj.mConnection = null;
294
        clonedObj.mReleaseConfigCollection = new ReleaseConfigData();
295
        clonedObj.mRunLevelCollection = new ArrayList<RunLevelData>();
296
        clonedObj.mPlannedPkgId = null;
297
        clonedObj.mDoNotCommit = false;
298
        clonedObj.mPlannedPkgVersion = null;
299
 
300
        return clonedObj;
301
    }
302
 
303
 
304
    /**constructor used when schema information is unknown eg location, username, password
305
     */
306
    public ReleaseManager()
307
    {
308
        // inherit mConnectionString, mUsername, mPassword
309
        mLogger.debug("ReleaseManager");
310
    }
311
 
312
    /**
313
     * Set the mode of operation to be either escrow mode or daemon mode
314
     * 
315
     * @param isDaemon True: Daemon Mode
316
     *               False: Escrow Mode
317
     */
318
    public void setDaemonMode(boolean isDaemon)
319
    {
320
        mDaemon = isDaemon;
7044 dpurdie 321
        mLogger.debug("DaemonMode:{}", mDaemon);
6914 dpurdie 322
    }
323
 
324
    /**
325
     * Clear mUseMutex
326
     * Used only in test mode to prevent the use of a mutex 
327
     */
328
    public static void setNoMutex()
329
    {
330
        mUseMutex = false;
331
    }
332
 
333
    /**
334
     * Return the state of mUseMutex
335
     * True indicates that the system must use a Mutex to access data
336
     */
337
    public static boolean getUseMutex()
338
    {
339
        return mUseMutex;
340
    }
341
 
342
    /** Returns the current time
343
     * 
344
     *  Overridden in ReleaseManagerUtf
345
     */
346
    public long currentTimeMillis()
347
    {
348
        return System.currentTimeMillis();
349
    }
350
 
351
    /** Returns the applications major version number
352
     *  Used to stamp the generated XML files to ensure that producer and consumer match 
353
     * 
354
     * Overridden in ReleaseManagerUtf
355
     */
356
    public String getMajorVersionNumber()
357
    {
358
        return this.getClass().getPackage().getSpecificationVersion();
359
    }
360
 
361
    /**connect to oracle - in a non planning mode 
362
     * Overridden in ReleaseManagerUtf 
363
     */
364
    public void connect() throws SQLException
365
    {
366
        mLogger.debug("connect");
367
        mNonPlanningConnection = connect( mNonPlanningConnection );
368
    }
369
 
370
    /**connect to oracle - to plan a build
371
     * @param   priority - true: Connect with a high priority (last planning session resulted in a build)
372
     */
373
    public void connectForPlanning( boolean priority ) throws SQLException
374
    {
375
        mLogger.debug("connectForPlanning");
376
 
377
        if ( !priority )
378
        {
379
            // limit only one thread with a low priority build requirement to connect
380
            if ( mLowPriorityQueue.isHeldByCurrentThread() )
381
            {
382
                // by design a thread must NOT connect multiple times
383
                // this is to ensure the lock is claimed only once
384
                mLogger.error("connectForPlanning thread already has the lock");
385
            }
386
            else
387
            {
388
                mLogger.debug("connectForPlanning calling lock");
389
                mLowPriorityQueue.lock();
390
                mLogger.debug("connectForPlanning called lock");
391
            }
392
        }
393
 
394
        // threads with a high priority build requirement are not subject to the mLowPriorityQueue
395
        mPlanningConnection = connect( mPlanningConnection );    
396
    }
397
 
398
    /**Connect to oracle - finally
399
     *  @param  session         - Lock item to use
400
     *  @param  connection      - Connection to use 
401
     */
402
    private RmConnection connect( RmConnection rmc ) throws SQLException
403
    {
404
        mLogger.debug("connect");
7137 dpurdie 405
 
6914 dpurdie 406
        try
407
        {
408
            if ( rmc.mSession.isHeldByCurrentThread() )
409
            {
410
                // by design a thread must NOT connect multiple times
411
                // this is to ensure the lock is claimed only once
412
                mLogger.error("connect thread already has the lock");
413
            }
414
            else
415
            {
416
                mLogger.debug("connect calling lock");
417
                rmc.mSession.lock();
418
                mLogger.debug("connect called lock");
419
            }
420
 
421
            if ( !mUseDatabase )
422
            {
423
                mLogger.info("connect !mUseDatabase");
424
            }
425
            else
426
            {
427
                // DEVI 46868
428
                // loop indefinitely until a connection attempt succeeds
429
                // unless the failure is on the first attempt
430
                boolean problemConnecting;
431
 
432
                do
433
                {
434
                    mLogger.debug("connect check connection");
435
                    problemConnecting = false;
436
 
437
                    try
438
                    {
439
                        if ( rmc.mConnection == null || ( rmc.mConnection != null && !rmc.mConnection.isValid(10) ) )
440
                        {
441
                            mLogger.warn("connect calling getConnection");
442
                            rmc.mConnection = DriverManager.getConnection(mConnectionString, mUsername, mPassword);
443
                            // when connection to the database is established, the connection, by default, is in auto-commit mode
444
                            // to adhere to the design in the use of select for update, it is crucial to turn auto-commit off
445
                            // this also improves performance
446
                            rmc.mConnection.setAutoCommit(false);
447
                        }
448
                    }
449
                    catch(SQLException e)
450
                    {
451
                        mLogger.warn("connect determined problem connecting");
452
                        problemConnecting = true;
453
                        try
454
                        {
455
                            // sleep 30 secs
456
                            mLogger.warn("connect getConnection failed. sleep 30secs");
457
                            Thread.sleep(30000);
458
                        }
459
                        catch (InterruptedException f)
460
                        {
461
                            mLogger.warn("connect caught InterruptedException");
462
                            Thread.currentThread().interrupt();
463
                        }
464
 
465
                        if ( rmc.mConnection == null )
466
                        {
467
                            // failed on first connection attempt - unlikely due to database loading - likely bad connection parameters
468
                            throw new SQLException();
469
                        }
470
                    }
471
                } while ( problemConnecting );
472
                mLogger.debug("connect checked connection");
473
            }
474
        }
475
        finally
476
        {
477
            mConnection = rmc.mConnection;
478
            mIsConnected = true;
479
            mLogger.debug("connect finally connection");
480
        }
481
        return rmc;
482
 
483
    }
484
 
485
    /**Disconnect from oracle Database 
486
     * <br>Is overridden in ReleaseManagerUtf for test purposes 
487
     */
488
    public void disconnect()
489
    {
490
        mLogger.debug("disconnect");
491
 
492
        disconnect( mNonPlanningConnection );
493
    }
494
 
495
    /**Disconnect from oracle
496
     * @param   priority    - True: High priority planning thread
497
     */
498
    public void disconnectForPlanning( boolean priority )
499
    {
500
        mLogger.debug("disconnectForPlanning");
501
 
502
        if ( !priority )
503
        {
504
            // allow another low priority thread to connect
505
            try {
506
                mLowPriorityQueue.unlock();
507
            }
508
            catch( IllegalMonitorStateException e ) {
7176 dpurdie 509
                mLogger.error("disconnectForPlanning. IllegalMonitorStateException exception {}", e);
6914 dpurdie 510
            }
511
        }
512
 
513
        disconnect( mPlanningConnection );
514
    }
515
 
516
    /**Disconnect from oracle
517
     * Internal oracle disconnection method. Wrapped by publicly available disconnection methods
518
     * @param   session. Session Lock
519
     */
520
    private void disconnect( RmConnection connection )
521
    {
522
        mLogger.debug("disconnect");
523
 
524
        // The planning connection is flagged to close on disconnect
525
        // This is an attempt to prevent database deadlocks - which have been seen
526
        // under unknown conditions.
527
        // Done before the lock is released
528
        if (connection.mCloseOnDisconnect)
529
        {
530
            mLogger.debug("disconnect close on disconnect");
531
        	connection.closeConnection();
532
        }
533
 
534
        // by design, a thread may call disconnect multiple times
535
        // this is a technique used in finally blocks
536
        // it is to ensure the lock is released in all cases
537
        // only unlock if it is held by this thread
538
        // when unlock is called on a ReentrantLock held by this thread
539
        // the hold count is decremented
540
        // connect should only let the hold count be incremented to 1
541
        // when the hold count is 0 the lock is released
542
        // and the ReentrantLock is no longer held by this thread
543
        // only call unlock when the lock is held by this thread
544
        if ( connection.mSession.isHeldByCurrentThread() )
545
        {
546
            mLogger.debug("disconnect calling unlock");
547
            try {
548
                connection.mSession.unlock();
549
            }
550
            catch (IllegalMonitorStateException e) {
7176 dpurdie 551
                mLogger.error("disconnect. IllegalMonitorStateException exception {}", e);
6914 dpurdie 552
            }
553
            mLogger.debug("disconnect called unlock");
554
        }
555
 
556
        mIsConnected = false;
557
    }
558
 
559
    /** Common processing SQL Exceptions
560
     *  If it is a connection error then a new SQLException will be thrown otherwise
561
     *  its an error with the SQL itself and a normal Exception will be thrown.
562
     *  
563
     * @param e                 - Exception being thrown
564
     * @param instanceId        - Method suffix to differentiate multiple methods of the same name
565
     * 
566
     * @throws SQLException
567
     * @throws Exception
568
     */
569
    void handleSQLException(SQLException e, String instanceId ) throws SQLException, Exception
570
    {
571
        String callingMethodName = Thread.currentThread().getStackTrace()[2].getMethodName() + instanceId ;
7044 dpurdie 572
        mLogger.error("{} sql exception:{}", callingMethodName, e.getMessage());
6914 dpurdie 573
 
574
        if ( mConnection == null || !mConnection.isValid(10) )
575
        {
7044 dpurdie 576
            mLogger.error( "{} database access error only", callingMethodName);
6914 dpurdie 577
            RmConnection.closeConnection(mConnection);
578
            throw new SQLException(e);
579
        }
580
        else
581
        {
7044 dpurdie 582
            mLogger.error( "{} show stopper", callingMethodName);
6914 dpurdie 583
            throw new Exception(callingMethodName + " show stopper");
584
        }
585
    }
586
 
587
    /** Claim the Build System Planning Lock
588
     * Essentially locks the row in the BUILD_SERVICE_CONFIG table with a service of MUTEX
589
     * for the duration of the transaction this prevents other MasterThreads from 
590
     * generating build files in parallel and hence prevents planned version numbering contention 
591
     */
592
    public void claimMutex() throws SQLException, Exception
593
    {
594
        mLogger.debug("claimMutex");
595
        mMutexState = "Claiming Mutex";
596
        if ( mUseDatabase && mUseMutex )
597
        {
598
            try
599
            {
600
                CallableStatement stmt = mConnection.prepareCall("select CONFIG from release_manager.BUILD_SERVICE_CONFIG WHERE SERVICE='MUTEX' FOR UPDATE");
7176 dpurdie 601
                mLogger.warn("claimMutex calling stmt.executeUpdate");
6914 dpurdie 602
                stmt.executeUpdate();
7176 dpurdie 603
                mLogger.warn("claimMutex called stmt.executeUpdate");
6914 dpurdie 604
                stmt.close();
605
                mDoNotCommit = true;
606
                mMutexState = "Holding Mutex";
607
            }
608
            catch ( SQLException e )
609
            {
610
                mMutexState = "Mutex Claim Exception";
611
                handleSQLException(e, "");
612
            }
613
 
614
            // about to start the planning process again, discard previous
615
            discardVersions();
616
        }
617
    }
618
 
619
    /** Release the Build System Planning Lock 
620
     *  Essentially unlocks the row in the BUILD_SERVICE_CONFIG table with a service of MUTEX
621
     */
622
    public void releaseMutex() throws SQLException, Exception
623
    {
624
        mLogger.debug("releaseMutex");
625
        mMutexState = "Releasing Mutex";
626
        if ( mUseDatabase )
627
        {
628
            try
629
            {
630
                mDoNotCommit = false;
7176 dpurdie 631
                mLogger.warn("releaseMutex calling commit");
6914 dpurdie 632
                commit();
7176 dpurdie 633
                mLogger.warn("releaseMutex called commit");
6914 dpurdie 634
                mMutexState = "Released Mutex";
635
            }
636
            catch ( SQLException e )
637
            {
638
                mMutexState = "Mutex Release Exception";
639
                handleSQLException(e, "");
640
            }
641
        }
642
    }
643
 
644
    /**central commit protection
645
     */
646
    private void commit() throws SQLException, Exception
647
    {
648
        mLogger.debug("commit");
649
        if ( mUseDatabase )
650
        {
651
            if ( mDoNotCommit )
652
            {
653
                mLogger.error("commit attempted commit with mDoNotCommit set, this is a programming error");
654
            }
655
            else
656
            {
657
                mConnection.commit();
658
            }
659
        }
660
    }
661
 
662
    /**Flag a Build System Pause in the database
663
     * This is aimed at stopping ALL daemons dead in the water
664
     * 
665
     * Used when handling an unsupported exception case in either the main or slave daemons
666
     * typically an SQLException other than a database connection related on
667
     *
668
     * @param mRecoverable  True: Recoverable pause wait until recovery is detected
669
     *                  <br>False: Unrecoverable pause. Wait for 20 minutes 
670
     */
671
    public void indefinitePause(boolean mRecoverable)
672
    {
673
        mLogger.debug("indefinitePause");
674
        if ( mUseDatabase )
675
        {
676
            String sqlStr;
677
            if ( mRecoverable) {
678
                sqlStr = "begin PK_BUILDAPI.set_infinite_pause(); end;";
679
            }
680
            else {
681
                sqlStr = "begin PK_BUILDAPI.set_finite_pause(20); end;";
682
            }
683
            try
684
            {
685
                connect();
686
                CallableStatement stmt = mConnection.prepareCall( sqlStr );
687
                stmt.executeUpdate();
688
                stmt.close();
689
                commit();
690
            }
691
            catch( SQLException e )
692
            {
693
                // do not throw Exception
694
                // this is part of Exception handling
7044 dpurdie 695
                mLogger.error( "indefinitePause caught SQLException {}", e.getMessage() );
6914 dpurdie 696
                RmConnection.closeConnection(mConnection);
697
            }
698
            catch( Exception e )
699
            {
7044 dpurdie 700
                mLogger.error( "indefinitePause caught Exception {}", e.getMessage() );
6914 dpurdie 701
            }
702
            finally
703
            {
704
                // this block is executed regardless of what happens in the try block
705
                // even if an exception is thrown
706
                // ensure disconnect
707
                try
708
                {
709
                    disconnect();
710
                }
711
                catch( Exception e )
712
                {
713
                    // do not throw Exception
714
                    // this is part of Exception handling
7044 dpurdie 715
                    mLogger.error( "indefinitePause2 caught Exception {}", e.getMessage() );
6914 dpurdie 716
                    RmConnection.closeConnection(mConnection);
717
                }
718
            }
719
        }
720
    }
721
 
722
    /**ensures a run_level_schedule row with a non null indefinite_pause column does not exist
723
     * this is aimed at resuming all daemons
724
     * 
725
     * Assumes connection to database has been established
726
     */
727
    public void resumeIndefinitePause() throws SQLException, Exception
728
    {
729
        mLogger.debug("resume");
730
        if ( mUseDatabase )
731
        {
732
            try
733
            {
734
                CallableStatement stmt = mConnection.prepareCall( "begin PK_BUILDAPI.SET_RESUME(); end;" );
735
                stmt.executeUpdate();
736
                stmt.close();
737
                commit();
738
            }
739
            catch ( SQLException e )
740
            {
741
                handleSQLException(e, "");
742
            }
743
        }
744
    }
745
 
746
 
747
    /**
748
     *  Only used in daemon mode
749
     *  Update the Database information to show the package being built
750
     * 
751
     * @param pkgId  Identify the package (name) being built
752
     * 
753
     * @param pkgVersion
754
     *                The version at which the package is being built
755
     * 
756
     * @param rtagId The release Id in which the package is being built
757
     * 
758
     * @exception SQLException
759
     * @exception Exception
760
     */
761
    void claimVersion(int pkgId, String pkgVersion, int rtagId) throws SQLException, Exception
762
    {
7044 dpurdie 763
        mLogger.debug("claimVersion {} {}", pkgId, pkgVersion);
6914 dpurdie 764
        if ( mUseDatabase )
765
        {
766
            CallableStatement stmt1 = null;
767
            try
768
            {
769
                if (isRtagIdConfigured( rtagId ))
770
                {
771
                    stmt1 = mConnection.prepareCall(
772
                            "insert into release_manager.planned_versions (pkg_id, pkg_version, planned_time) values (?,?, sysdate)");
773
                    stmt1.setInt(1, pkgId);
774
                    stmt1.setString(2, pkgVersion);
775
                    stmt1.executeUpdate();
776
 
777
                    mPlannedPkgId = String.valueOf(pkgId);
778
                    mPlannedPkgVersion = pkgVersion;
779
                }
780
            }
781
            catch ( SQLException e )
782
            {
783
                handleSQLException(e, "");
784
            }
785
            finally {
786
                if (stmt1 != null)
787
                    stmt1.close();
788
            }
789
        }
790
    }
791
 
792
    /**Only used in daemon mode
793
     * <br>Delete planned package package information from the last planned build
794
     * <p>
795
     * Note: There is an aging process to cleanup entries that are left around due to
796
     *       unforeseen errors.
797
     * <p>      
798
     * Resets mPlannedPkgId and mPlannedPkgVersion to null
799
     * 
800
     * @exception   SQLException
801
     * @exception   Exception
802
     */
803
    public void discardVersion() throws SQLException, Exception
804
    {
7176 dpurdie 805
        mLogger.warn("discardVersion");
6914 dpurdie 806
 
807
        if ( mPlannedPkgId != null && mPlannedPkgVersion != null )
808
        {
809
            try
810
            {
811
                connect();
812
                CallableStatement stmt = mConnection.prepareCall(
813
                    "delete from release_manager.planned_versions" +
7169 dpurdie 814
                    " where pkg_id=? and pkg_version=?");
815
                stmt.setString(1, mPlannedPkgId);
816
                stmt.setString(2, mPlannedPkgVersion);
6914 dpurdie 817
                stmt.executeUpdate();
818
                stmt.close();
819
                commit();
820
                mPlannedPkgId = null;
821
                mPlannedPkgVersion = null;
822
            }
823
            catch ( SQLException e )
824
            {
825
                handleSQLException(e, "");
826
            }
827
            finally
828
            {
829
                disconnect();
830
            }
831
        }
832
    }
833
 
834
    /** Delete planned versions over 24 hours old (rounded to the nearest hour that is) 
835
     *  Only used in daemon mode 
836
     */
837
    private void discardVersions() throws SQLException, Exception
838
    {
839
        mLogger.debug("discardVersions");
840
        try
841
        {
842
            // housekeeping whilst the daemon has the mutex
843
            // trunc(sysdate, 'hh') returns the time now rounded to the nearest hour
844
            // trunc(sysdate, 'hh') - 1 returns the time 24 hours ago rounded to the nearest hour
845
            // this statement does not return any rows when planned_time is null, though this should never be the case
846
            CallableStatement stmt = mConnection.prepareCall("delete from release_manager.planned_versions where planned_time < trunc(sysdate, 'hh') - 1");
847
            stmt.executeUpdate();
848
            stmt.close();
849
        }
850
        catch ( SQLException e )
851
        {
852
            handleSQLException(e, "");
853
        }
854
    }
855
 
856
    /**Update the Database information to show that a package is being built 
857
     * Only used in daemon mode
858
     * 
859
     *  @param rconId - Identifies the Release Config table entry
860
     *  @param pkgId - Identifies the name of the package being built
861
     *  @param pkgPvId - Identifies the packageVersion the build is based upon
862
     */
863
    public void setCurrentPackageBeingBuilt(int rconId, int pkgId, int pkgPvId) throws SQLException, Exception
864
    {
7176 dpurdie 865
        mLogger.warn("setCurrentPackageBeingBuilt {}", rconId);
6914 dpurdie 866
        if ( mUseDatabase )
867
        {
868
            CallableStatement stmt = null;
869
            try
870
            {
871
                connect();
872
 
873
                stmt = mConnection.prepareCall(
874
                        "update release_manager.run_level rl"+
875
                        " set current_pkg_id_being_built=?"+
876
                        "    ,current_pv_id=?" +
877
                        "    ,last_build=sysdate" +
878
                        " where rl.rcon_id=?" 
879
                        );
880
                stmt.setInt(1, pkgId);
881
                stmt.setInt(2, pkgPvId);
882
                stmt.setInt(3, rconId);                    
883
                stmt.executeUpdate();
884
 
885
                commit();
886
            }
887
            catch ( SQLException e )
888
            {
889
                handleSQLException(e, "");
890
            }
891
            finally
892
            {
893
                // this block is executed regardless of what happens in the try block
894
                // even if an exception is thrown
895
                // ensure disconnect
896
                if (stmt != null)
897
                    stmt.close();
898
                disconnect();
899
            }
900
        }
901
    }
902
 
903
 
904
    /**Update the Database information to show that no package is being built 
905
     * Only used in daemon mode
906
     * 
907
     *  @param rconId - Identifies the Release Config table entry
908
     */
909
    public void clearCurrentPackageBeingBuilt(int rconId) throws SQLException, Exception
910
    {
7176 dpurdie 911
        mLogger.warn("clearCurrentPackageBeingBuilt {}", rconId);
6914 dpurdie 912
        if ( mUseDatabase )
913
        {
914
            try
915
            {
916
                connect();
917
 
918
                CallableStatement stmt4 = mConnection.prepareCall(
919
                        "update release_manager.run_level" +
920
                        " set current_pkg_id_being_built=NULL,"+
921
                        "     current_pv_id=NULL," +
922
                        "     current_build_files=NULL" +
7169 dpurdie 923
                        " where rcon_id=?"
6914 dpurdie 924
                         );
7169 dpurdie 925
                stmt4.setInt(1, rconId);
6914 dpurdie 926
                stmt4.executeUpdate();
927
                stmt4.close();
928
                commit();
929
            }
930
            catch ( SQLException e )
931
            {
932
                handleSQLException(e, "");
933
            }
934
            finally
935
            {
936
                // this block is executed regardless of what happens in the try block
937
                // even if an exception is thrown
938
                // ensure disconnect
939
                disconnect();
940
            }
941
        }
942
    }
943
 
944
    /**
945
     * Executes the AutoMakeRelease stored procedure with the passed parameters
946
     *          Handles database connection/disconnection
947
     * 
948
     * @param mReporting
949
     * 
950
     * @return A publishing error
951
     *         True: A publishing error that only affect the current package
952
     *         False: No publishing error
953
     * @exception SQLException
954
     * @exception Exception A publishing error that affects the entire build system.
955
     *                      This will cause an 'indefinite pause'
956
     */
957
    public boolean autoMakeRelease(ReportingData mReporting) throws SQLException, Exception
958
    {
959
 
960
        mReporting.errMsg = null;
7044 dpurdie 961
        mLogger.debug("autoMakeRelease {}", mReporting.packageName);
6914 dpurdie 962
        if ( mUseDatabase )
963
        {
964
            try
965
            {
966
                //  Create an array of dependencies
967
                //  Convert the string mReporting.packageDepends into an array
968
                //      mReporting.packageDepends is of the form 'PackageName','PackageVersion';'PackageName2','PackageVersion2'
969
                String [] depArrayData = mReporting.packageDepends.split(";"); 
970
                ArrayDescriptor desc = ArrayDescriptor.createDescriptor("RELEASE_MANAGER" + "." + "RELMGR_VARCHAR2_TAB_T", mConnection);
971
                Array depArray = new oracle.sql.ARRAY(desc, mConnection, depArrayData);                
972
 
973
                connect();
974
                CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_RMAPI.AUTO_MAKE_VCSRELEASE2(?,?,?,?,?,?,?,?); end;" );
975
                stmt.registerOutParameter( 1, Types.INTEGER);
976
                stmt.setLong( 2, mReporting.rtagId );
977
                stmt.setString( 3, mReporting.packageName );
978
                stmt.setString( 4, mReporting.packageExtension );
979
                stmt.setString( 5, mReporting.packageVersion );
980
                stmt.setString( 6, mReporting.newVcsTag );
981
                stmt.setArray ( 7, depArray );
982
                stmt.setInt   ( 8, mReporting.isRipple ? 1 : 0 );
983
                stmt.setString( 9, "buildadm" );
984
                stmt.executeUpdate();
985
                int result = stmt.getInt( 1 );
986
 
987
                //
988
                //  Return values
989
                //      >0 PVID of package
990
                //      -1 Package not found in pending table
991
                //      -2 Package already exists
992
                //      -3 Not approved for auto build
993
                //      -4 Package Migrated to SVN being built from CC tag
994
                //      -5 Rippled Package: Source path changed
995
                //  Sql Application Errors cause an SQLException
996
                //         Rtagid is NULL
997
                //         No Package Name
998
                //         No Package Version
999
                //         No Package VCS
1000
                //         Bad IsRipple value
1001
                //         No User Name
1002
                //         Malformed VCS Tag
1003
                //         Database missing VCS tag
1004
                //         Invalid UserName
1005
                //
1006
 
1007
                //
1008
                //  Report per-package errors directly
1009
                //  Exceptions are for errors that need to halt the entire system
1010
                //
1011
                if ( result <= 0 )
1012
                {
7044 dpurdie 1013
                    mLogger.error("autoMakeRelease PK_RMAPI.AUTO_MAKE_VCSRELEASE failed, returned {}", result);
6914 dpurdie 1014
                    if ( result == -4 ) {
1015
                        mReporting.errMsg = "Package migrated to SVN being built from CC tag";
1016
                    } else if ( result == -3 ) {
1017
                        mReporting.errMsg = "Package not approved for autobuild";
1018
                    } else if ( result == -2 ) {
1019
                        // This is OK
1020
                    }  else if ( result == -1 ) {
1021
                        mReporting.errMsg = "Package Version no longer pending";
1022
                    }  else if ( result == -5 ) {
1023
                        mReporting.errMsg = "VCS Source path changed in ripple build";
1024
                    } else {
1025
                        // Don't know this error - so its fatal
1026
                        throw new Exception("autoMakeRelease show stopper PK_RMAPI.AUTO_MAKE_VCSRELEASE failed, returned " + result);
1027
                    }
1028
                }
1029
                else
1030
                {
1031
 
1032
                    //  Now that the package-version has been created in the database, we have the pv_id of the
1033
                    //  new package. Use this in the reporting process.
1034
                    mReporting.packageVersionId = result;
1035
                }
1036
 
1037
                stmt.close();
1038
                commit();
1039
            }
1040
            catch ( SQLException e )
1041
            {
1042
                handleSQLException(e, "");
1043
            }
1044
            finally
1045
            {
1046
                // this block is executed regardless of what happens in the try block
1047
                // even if an exception is thrown
1048
                // ensure disconnect
1049
                disconnect();
1050
            }
1051
        }
1052
        return (mReporting.errMsg != null);
1053
    }
1054
 
1055
    /** Executes the insertPackageMetrics stored procedure with the passed parameters
1056
     *  Handles database connection/disconnection
1057
     */
1058
    public void insertPackageMetrics(int mRtagId, String packageName, 
1059
            String packageExtension, String metrics) throws SQLException, Exception
1060
    {
7044 dpurdie 1061
        mLogger.debug("insertPackageMetrics {}", packageName);
6914 dpurdie 1062
        if ( mUseDatabase )
1063
        {
1064
            try
1065
            {
1066
                connect();
1067
                CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_RMAPI.INSERT_PACKAGE_METRICS(?,?,?,?); end;" );
1068
                stmt.registerOutParameter( 1, Types.INTEGER);
1069
                stmt.setInt   ( 2, mRtagId );
1070
                stmt.setString( 3, packageName );
1071
                stmt.setString( 4, packageExtension );
1072
                stmt.setString( 5, metrics );
1073
                stmt.executeUpdate();
1074
                int result = stmt.getInt( 1 );
1075
 
1076
                if ( result != 0 )
1077
                {
1078
                    // flag build failure
7044 dpurdie 1079
                    mLogger.error("insertPackageMetrics show stopper PK_RMAPI.INSERT_PACKAGE_METRICS failed, returned {}", result);
6914 dpurdie 1080
                    throw new Exception("insertPackageMetrics show stopper PK_RMAPI.INSERT_PACKAGE_METRICS failed, returned" + result);
1081
                }
1082
                stmt.close();
1083
                commit();
1084
            }
1085
            catch ( SQLException e )
1086
            {
1087
                handleSQLException(e, "");
1088
            }
1089
            finally
1090
            {
1091
                // this block is executed regardless of what happens in the try block
1092
                // even if an exception is thrown
1093
                // ensure disconnect
1094
                disconnect();
1095
            }
1096
        }
1097
    }
1098
 
1099
    /**
1100
     * Add entry to the Build_Instance table
1101
     * Returns the build instance number. This will be used to cross reference unit tests results
7253 dpurdie 1102
     * @param rtagId
1103
     * @param pvId
1104
     * @param BuildReason
1105
     * @param buildRef 
6914 dpurdie 1106
     * 
1107
     * @throws throws SQLException, Exception 
1108
     * 
1109
     */
7253 dpurdie 1110
    public int createBuildInstance(int rtagId, int pvId, BuildReason reason, String buildRef) throws SQLException, Exception
6914 dpurdie 1111
    {
1112
        int buildId = 0;
1113
 
7044 dpurdie 1114
        mLogger.debug("createBuildInstance {}:{}", rtagId, pvId);
6914 dpurdie 1115
        if ( mUseDatabase )
1116
        {
1117
            try
1118
            {
1119
                connect();
7253 dpurdie 1120
                CallableStatement stmt = mConnection.prepareCall("begin ? := PK_RMAPI.new_build_instance(?,?,?,?); end;");
6914 dpurdie 1121
                stmt.registerOutParameter( 1, Types.INTEGER);
1122
                stmt.setLong( 2,rtagId );
1123
                stmt.setLong( 3,pvId );
1124
                stmt.setString( 4,reason.toString() );
7253 dpurdie 1125
                stmt.setString( 5,buildRef);
6914 dpurdie 1126
                stmt.executeUpdate();
1127
                buildId = stmt.getInt( 1 );
1128
 
7044 dpurdie 1129
                mLogger.warn("createBuildInstance: Build Instance ID: {}", buildId);
6914 dpurdie 1130
 
1131
                stmt.close();
1132
                commit();
1133
            }
1134
            catch ( SQLException e )
1135
            {
1136
                handleSQLException(e, "");
1137
            }
1138
            finally
1139
            {
1140
                // this block is executed regardless of what happens in the try block
1141
                //      even if an exception is thrown
1142
                //      ensure disconnect
1143
                disconnect();
1144
            }
1145
        }
1146
        return buildId;
1147
    }
1148
 
1149
    /**
1150
     * Update the Build_Instance table.
1151
     * <br>Record the state of the current build in the database
1152
     * 
1153
     * @param buildId  - Build ID of build
1154
     * @param pvId     - PV_ID of the build
1155
     * @param result   - Outcome  of the build
1156
     * 
1157
     * Returns the internal error code. <0 == error
1158
     * 
1159
     * @throws throws SQLException, Exception 
1160
     * 
1161
     */
1162
    public int updateBuildInstance(int buildID, int pvId, BuildResult result) throws SQLException, Exception
1163
    {
1164
        int rv = 0;
1165
 
7044 dpurdie 1166
        mLogger.debug("updateBuildInstance {}:{}:{}", buildID, pvId, result);
6914 dpurdie 1167
        if ( mUseDatabase )
1168
        {
1169
            try
1170
            {
1171
                connect();
1172
 
1173
                String sql = "begin ? := PK_RMAPI.update_build_instance(?,?,?); end;";
1174
 
1175
                CallableStatement stmt = mConnection.prepareCall(sql);
1176
                stmt.registerOutParameter( 1, Types.INTEGER);
1177
                stmt.setLong( 2,buildID );
1178
                stmt.setLong( 3,pvId );
1179
                stmt.setString( 4,result.toString() );
1180
                stmt.executeUpdate();
1181
                rv = stmt.getInt( 1 );
1182
 
7044 dpurdie 1183
                mLogger.warn("updateBuildInstance: Result: {}", rv);
6914 dpurdie 1184
 
1185
                stmt.close();
1186
                commit();
1187
            }
1188
            catch ( SQLException e )
1189
            {
1190
                handleSQLException(e, "");
1191
            }
1192
            finally
1193
            {
1194
                // this block is executed regardless of what happens in the try block
1195
                //      even if an exception is thrown
1196
                //      ensure disconnect
1197
                disconnect();
1198
            }
1199
        }
1200
        return rv;
1201
    }
1202
 
1203
    /**
7253 dpurdie 1204
     * Remove the BuildRef once the build log has been deleted
1205
     * 
1206
     * @param rtagId       - Release Id
1207
     * @param buildRef     - Build Ref
1208
     * 
1209
     * Returns the internal error code. <0 == error
1210
     * 
1211
     * Handles exceptions locally as its called in a context with little handling 
1212
     * 
1213
     */
1214
    public int removeBuildRef(int rtagId, String buildRef)
1215
    {
1216
        int rv = 0;
1217
 
1218
        mLogger.debug("removeBuildRef {}:{}", rtagId, buildRef);
1219
        if ( mUseDatabase )
1220
        {
1221
            try
1222
            {
1223
                connect();
1224
 
1225
                String sql = "begin ? := PK_RMAPI.update_build_ref(?,?); end;";
1226
 
1227
                CallableStatement stmt = mConnection.prepareCall(sql);
1228
                stmt.registerOutParameter( 1, Types.INTEGER);
1229
                stmt.setLong( 2,rtagId );
1230
                stmt.setString( 3,buildRef );
1231
                stmt.executeUpdate();
1232
                rv = stmt.getInt( 1 );
1233
 
1234
                mLogger.warn("removeBuildRef: Result: {}", rv);
1235
 
1236
                stmt.close();
1237
                commit();
1238
            }
1239
            catch ( SQLException e )
1240
            {
1241
                mLogger.error("{} sql exception:{}", "removeBuildRef", e.getMessage());
1242
 
1243
            } catch (Exception e) {
1244
                mLogger.error("{} excpetion:{}", "removeBuildRef", e);
1245
            }
1246
            finally
1247
            {
1248
                // this block is executed regardless of what happens in the try block
1249
                //      even if an exception is thrown
1250
                //      ensure disconnect
1251
                disconnect();
1252
            }
1253
        }
1254
        return rv;
1255
    }
1256
 
1257
    /**
6914 dpurdie 1258
     * Insert Test Results into Release Manager
1259
     * Manage connection and disconnection
1260
     * 
1261
     * @param buildId
1262
     * @param btr
1263
     * @throws Exception, SQLException 
1264
     */
1265
    public void insertTestResults(int buildId, BuildTestResults btr) throws Exception, SQLException
1266
    {
1267
        if (buildId <= 0)
1268
        {
1269
            mLogger.warn("insertTestResults: Invalid build Id");
1270
            return;
1271
        }
1272
 
1273
        if ( !mUseDatabase || !btr.mResultsFound )
1274
        {
1275
            return;
1276
        }
1277
 
7044 dpurdie 1278
        mLogger.warn("insertTestResults: {}, Number:{}", buildId, btr.mTestResults.size() );
6914 dpurdie 1279
        try
1280
        {
1281
            connect();
1282
            String sql = "BEGIN ? := PK_RMAPI.insert_test_run(?, ?, ?, ?, ?, ?, ?);end;";
1283
            CallableStatement stmt = mConnection.prepareCall(sql);
1284
            stmt.registerOutParameter( 1, Types.INTEGER);
1285
            stmt.setLong(2, buildId);
1286
            Clob myClob = mConnection.createClob();
1287
 
1288
            for (int ii = 0; ii < btr.mTestResults.size(); ii++)
1289
            {
1290
                BuildTestResults.testResultData td = btr.mTestResults.get(ii);
1291
                if (td.platform != null)
1292
                {
1293
                    stmt.setString(3, td.testName);
1294
                    stmt.setString(4, td.outcome);
1295
                    stmt.setString(5, td.platform);
1296
                    stmt.setString(6, td.type);
1297
                    if (td.duration ==  null) {
1298
                        stmt.setNull(7, Types.NUMERIC);
1299
                    } else {
1300
                        stmt.setLong  (7, td.duration);
1301
                    }
1302
 
1303
                    // Insert CLOB data, or a null
1304
                    if (td.message == null)
1305
                    {
1306
                        stmt.setNull(8,Types.CLOB);
1307
                    }
1308
                    else
1309
                    {
1310
                        myClob.truncate(0);
1311
                        myClob.setString(1, td.message);
1312
                        stmt.setClob(8, myClob);
1313
                    }
1314
 
1315
                    stmt.execute();
1316
                    int rv = stmt.getInt( 1 );
1317
 
1318
                    if (rv != 1)
1319
                    {
7033 dpurdie 1320
                        mLogger.error("insertTestResults show stopper. Insert error");
6914 dpurdie 1321
                        throw new Exception("insertTestResults show stopper. Insert error");
1322
                    }
1323
                }
1324
            }
1325
            stmt.close();
1326
 
1327
        }
1328
        catch ( SQLException e )
1329
        {
1330
            handleSQLException(e, "");
1331
        }
1332
        finally
1333
        {
1334
            // this block is executed regardless of what happens in the try block
1335
            // even if an exception is thrown
1336
            // ensure disconnect
1337
            disconnect();
1338
        }
1339
    }
1340
 
1341
    /**executes the get_daemon_inst function with the passed parameters
7023 dpurdie 1342
     * @param   di          - Daemon Instruction Control Data Information
1343
     * 
6914 dpurdie 1344
     * @return  true if an instruction exists - for use in a while loop
1345
     */
7023 dpurdie 1346
    public boolean getDaemonInst(DaemonInstruction di ) throws SQLException, Exception
6914 dpurdie 1347
    {
7044 dpurdie 1348
        mLogger.debug("getDaemonInst {}", di.instruction);
6914 dpurdie 1349
        boolean retVal = false;
1350
 
1351
        if ( mUseDatabase )
1352
        {
1353
            try
1354
            {
7023 dpurdie 1355
                CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_BUILDAPI.GET_DAEMON_INST(?,?,?,?,?,?,?); end;" );
6914 dpurdie 1356
                stmt.registerOutParameter(1, Types.INTEGER);
1357
                stmt.registerOutParameter(3, Types.INTEGER);
1358
                stmt.registerOutParameter(4, Types.INTEGER);
1359
                stmt.registerOutParameter(5, Types.INTEGER);
1360
                stmt.registerOutParameter(6, Types.INTEGER);
1361
                stmt.registerOutParameter(7, Types.INTEGER);
7023 dpurdie 1362
                stmt.setInt(2, di.rtag_id );
1363
                stmt.setInt( 3, di.instruction );
1364
                stmt.setInt( 4, di.opCode );
1365
                stmt.setInt(8, di.expired ? 1 : 0);
6914 dpurdie 1366
                stmt.execute();
1367
                int result = stmt.getInt( 1 );
1368
 
1369
                if ( result == 1 )
1370
                {
1371
                    retVal = true;
7023 dpurdie 1372
                    di.instruction = stmt.getInt( 3 );
1373
                    di.pvId = stmt.getInt( 5 );
1374
                    di.userId = stmt.getInt( 6 );
6914 dpurdie 1375
 
1376
                    //
1377
                    //  Convert userId into an email address
1378
                    //
1379
                    CallableStatement stmt1 = mConnection.prepareCall(
7169 dpurdie 1380
                            "select user_email from release_manager.users where user_id=?");
1381
                    stmt1.setInt(1, di.userId);
6914 dpurdie 1382
                    ResultSet rset1 = stmt1.executeQuery();
1383
 
1384
                    while( rset1.next() )
1385
                    {
7023 dpurdie 1386
                        di.userEmail = rset1.getString("user_email");
6914 dpurdie 1387
                        if (rset1.wasNull())
1388
                        {
7023 dpurdie 1389
                            di.userEmail = "";
6914 dpurdie 1390
                        }
1391
                    }
1392
 
1393
                    rset1.close();
1394
                    stmt1.close();
1395
 
1396
                }
1397
 
1398
                stmt.close();
1399
 
1400
            }
1401
            catch ( SQLException e )
1402
            {
1403
                handleSQLException(e, "");
1404
            }
1405
        }
1406
        return retVal;
1407
    }
7023 dpurdie 1408
 
6914 dpurdie 1409
    /** Mark a Daemon Instruction as in-progress
1410
     *  Assumes that a database connection has been established
1411
     *  Assumes that the connection is within a Mutex session and the database commit will be done elsewhere
1412
     *  
1413
     *  @param  instruction - PVID of the daemon instruction to process
1414
     */
1415
    public void markDaemonInstInProgress(final int instruction) throws SQLException, Exception
1416
    {
7044 dpurdie 1417
        mLogger.debug("markDaemonInstInProgress {}", instruction);
6914 dpurdie 1418
 
1419
        if ( mUseDatabase )
1420
        {
1421
            try
1422
            {
1423
                CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.MARK_DAEMON_INST_IN_PROGRESS(?)" );
1424
                stmt.setInt( 1, instruction );
1425
                stmt.executeUpdate();
1426
                stmt.close();
1427
            }
1428
            catch ( SQLException e )
1429
            {
1430
                handleSQLException(e, "");
1431
            }
1432
        }
1433
    }
1434
 
1435
    /** Mark a Daemon Instruction as completed
1436
     *  Will establish (and release) a database connection if non is currently open
1437
     *  Will commit the change - unless commits have been disabled within a Mutex session
1438
     *  
1439
     *  @param  instruction - PVID of Daemon Instruction to process
1440
     */
1441
    public void markDaemonInstCompleted(final int instruction) throws SQLException, Exception
1442
    {
7044 dpurdie 1443
        mLogger.debug("markDaemonInstCompletedConnect {}", instruction);
6914 dpurdie 1444
        boolean connectionCreated = false;
1445
 
1446
        try
1447
        {
1448
            if (! mIsConnected)
1449
            {
1450
                connect();
1451
                connectionCreated = true;
1452
            }
1453
 
1454
            if ( mUseDatabase )
1455
            {
1456
                try
1457
                {
1458
                    CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.MARK_DAEMON_INST_COMPLETED(?)" );
1459
                    stmt.setInt( 1, instruction );
1460
                    stmt.executeUpdate();
1461
                    stmt.close();
1462
                }
1463
                catch ( SQLException e )
1464
                {
1465
                    handleSQLException(e, "");
1466
                }
1467
            }
1468
 
1469
            if ( ! mDoNotCommit )
1470
            {
1471
                commit();
1472
            }
1473
        }
1474
        catch ( SQLException e )
1475
        {
1476
            handleSQLException(e, "");
1477
        }
1478
        finally
1479
        {
1480
            // this block is executed regardless of what happens in the try block
1481
            // even if an exception is thrown
1482
            // ensure disconnect
1483
            if (connectionCreated)
1484
            {
1485
                disconnect();
1486
            }
1487
        }
1488
    }
1489
 
1490
    /**
1491
     * Determine the RTAG_ID associated with a given SBOM
1492
     * Sets up mRtagId and mSbomId 
1493
     *  
1494
     * Overridden in ReleaseManagerUtf
1495
     * 
1496
     * @param sbom_id An sbom_id to process
1497
     * 
1498
     * @return The SBOM's RTAG_ID, or zero if none was found
1499
     * @exception SQLException
1500
     */
1501
    public int queryRtagIdForSbom(int sbom_id) throws SQLException
1502
    {
1503
        int rtagId = 0;
1504
 
7169 dpurdie 1505
        CallableStatement stmt = mConnection.prepareCall("select b.rtag_id_fk from deployment_manager.boms b where b.bom_id=?");
1506
        stmt.setInt(1, sbom_id);
6914 dpurdie 1507
        ResultSet rset = stmt.executeQuery();
1508
        while( rset.next() )
1509
        {
1510
            rtagId = rset.getInt("rtag_id_fk");
1511
        }
1512
        rset.close();
1513
        stmt.close();
1514
 
1515
        return rtagId;
1516
     }
1517
 
1518
 
1519
    /**In daemon mode
1520
     * Returns a concatenation of the proj_name and rtag_name 
1521
     *  
1522
     * In escrow mode
1523
     * Returns a concatenation of the proj_name, branch_name, bom_version and bom_lifecycle 
1524
     *  
1525
     * Overridden in ReleaseManagerUtf 
1526
     */
1527
    public String queryBaselineName(int baseline) throws SQLException, Exception
1528
    {
7044 dpurdie 1529
        mLogger.debug("queryBaselineName {}", mDaemon);
6914 dpurdie 1530
        StringBuilder retVal = new StringBuilder();
1531
 
1532
        String sql = "";
1533
 
1534
        if ( mDaemon )
1535
        {
1536
            sql = "select p.proj_name, rt.rtag_name" +
1537
                  " from release_manager.projects p, release_manager.release_tags rt" +
7169 dpurdie 1538
                  " where rt.rtag_id=? and p.proj_id=rt.proj_id";
6914 dpurdie 1539
        }
1540
        else
1541
        {
1542
            sql = "select dp.proj_name, br.branch_name, b.bom_version, b.bom_lifecycle" +
1543
                  " from deployment_manager.dm_projects dp, deployment_manager.branches br, deployment_manager.boms b" +
7169 dpurdie 1544
                  " where b.bom_id=? and br.branch_id=b.branch_id and dp.proj_id=br.proj_id";
6914 dpurdie 1545
        }
1546
 
1547
        try
1548
        {
1549
            CallableStatement stmt = mConnection.prepareCall(sql);
7169 dpurdie 1550
            stmt.setInt(1, baseline);
6914 dpurdie 1551
            ResultSet rset = stmt.executeQuery();
1552
 
1553
            while( rset.next() )
1554
            {
1555
                String proj_name = rset.getString("proj_name");
1556
 
1557
                if ( proj_name != null )
1558
                {
1559
                    retVal.append(proj_name);
1560
                }
1561
 
1562
                if ( mDaemon )
1563
                {
1564
                    String rtag_name = rset.getString("rtag_name");
1565
 
1566
                    if ( rtag_name != null )
1567
                    {
1568
                        retVal.append(" > ").append(rtag_name);
1569
                    }
1570
                }
1571
                else
1572
                {
1573
                    String branch_name = rset.getString("branch_name");
1574
 
1575
                    if ( branch_name != null )
1576
                    {
1577
                        retVal.append(" > ").append(branch_name);
1578
                    }
1579
 
1580
                    String bom_version = rset.getString("bom_version");
1581
 
1582
                    if ( bom_version != null )
1583
                    {
1584
                        retVal.append(" ").append(bom_version);
1585
                    }
1586
 
1587
                    String bom_lifecycle = rset.getString("bom_lifecycle");
1588
 
1589
                    if ( bom_lifecycle != null )
1590
                    {
1591
                        retVal.append(".").append(bom_lifecycle);
1592
                    }
1593
                }
1594
            }
1595
 
1596
            rset.close();
1597
            stmt.close();
1598
        }
1599
        catch ( SQLException e )
1600
        {
1601
            handleSQLException(e, "");
1602
        }
1603
 
7176 dpurdie 1604
        mLogger.debug("queryBaselineName returned {}", retVal);
6914 dpurdie 1605
        return retVal.toString();
1606
    }
1607
 
1608
    /**only used in daemon mode
1609
     *   select config from release_manager.build_service_config where service='MAIL SERVER';
1610
     * returns the configured service 
1611
     *  
1612
     * Overridden in ReleaseManagerUtf 
1613
     *  
1614
     */
1615
    public String queryMailServer() throws SQLException, Exception
1616
    {
1617
        mLogger.debug("queryMailServer");
1618
        String retVal = "";
1619
 
1620
 
1621
        try
1622
        {
1623
            CallableStatement stmt = mConnection.prepareCall("select config from release_manager.build_service_config where service='MAIL SERVER'");
1624
            ResultSet rset = stmt.executeQuery();
1625
 
1626
            while( rset.next() )
1627
            {
1628
                String config = rset.getString("config");
1629
 
1630
                if ( config != null )
1631
                {
1632
                    retVal = config;
1633
                    break;
1634
                }
1635
            }
1636
 
1637
            rset.close();
1638
            stmt.close();
1639
        }
1640
        catch ( SQLException e )
1641
        {
1642
            handleSQLException(e, "");
1643
        }
1644
 
1645
 
7176 dpurdie 1646
        mLogger.debug("queryMailServer returned {}", retVal);
6914 dpurdie 1647
        return retVal;
1648
    }
1649
 
1650
    /**only used in daemon mode
1651
     * returns the configured service 
1652
     *  
1653
     * Overridden in ReleaseManagerUtf 
1654
     *  
1655
     */
1656
    public String queryMailSender() throws SQLException, Exception
1657
    {
1658
        mLogger.debug("queryMailSender");
1659
        String retVal = "";
1660
 
1661
        try
1662
        {
1663
            CallableStatement stmt = mConnection.prepareCall("select config from release_manager.build_service_config where service='BUILD FAILURE MAIL SENDER'");
1664
            ResultSet rset = stmt.executeQuery();
1665
 
1666
            while( rset.next() )
1667
            {
1668
                String config = rset.getString("config");
1669
 
1670
                if ( config != null )
1671
                {
1672
                    retVal = config;
1673
                    break;
1674
                }
1675
            }
1676
 
1677
            rset.close();
1678
            stmt.close();
1679
        }
1680
        catch ( SQLException e )
1681
        {
1682
            handleSQLException(e, "");
1683
        }
1684
 
7044 dpurdie 1685
        mLogger.debug("queryMailSender returned {}", retVal);
6914 dpurdie 1686
        return retVal;
1687
    }
1688
 
1689
    /**only used in daemon mode
1690
     * returns the configured global email addresses 
1691
     *  
1692
     * Overridden in ReleaseManagerUtf 
1693
     */
1694
    public String queryGlobalAddresses() throws SQLException, Exception
1695
    {
1696
        mLogger.debug("queryGlobalAddresses");
1697
        String retVal = "";
1698
 
1699
        try
1700
        {
1701
            CallableStatement stmt = mConnection.prepareCall(
1702
                    "select u.user_email from release_manager.build_service_config bsc, release_manager.users u " +
1703
                            "where bsc.service='GLOBAL EMAIL ADDRESS LIST' and u.full_name=bsc.config"
1704
                    );
1705
            ResultSet rset = stmt.executeQuery();
1706
 
1707
            while( rset.next() )
1708
            {
1709
                String email = rset.getString("user_email");
1710
 
1711
                if ( email != null )
1712
                {
1713
                    retVal = email;
1714
                    break;
1715
                }
1716
            }
1717
 
1718
            rset.close();
1719
            stmt.close();
1720
        }
1721
        catch ( SQLException e )
1722
        {
1723
            handleSQLException(e, "");
1724
        }
1725
 
1726
 
7044 dpurdie 1727
        mLogger.debug("queryGlobalAddresses returned {}", retVal);
6914 dpurdie 1728
        return retVal;
1729
    }
1730
 
1731
    /**
1732
     * Determine a list of global, project wide and release email recipients
1733
     * All emails will be sent to people on this list
1734
     * @param baseline - an rtag_id
1735
     * @throws SQLException
1736
     * @returns String vector of email addresses
1737
     */
1738
    public List<String> queryProjectEmail(int baseline) throws SQLException
1739
    {
1740
        //
1741
        //  Get Global and Project Wide email information
1742
        //
1743
        mLogger.debug("queryGlobalandProjectEmail");
1744
        ArrayList<String> emailCollection = new ArrayList<String>();
1745
 
1746
        CallableStatement stmt0 = mConnection.prepareCall(
1747
                "select u.user_email " +
1748
                        "from release_manager.autobuild_failure af, " + 
1749
                        "release_manager.members_group mg, " + 
1750
                        "release_manager.users u, " + 
1751
                        "release_manager.views v, " + 
1752
                        "release_manager.release_tags rt " +
7169 dpurdie 1753
                        "where rt.rtag_id=? " +
6914 dpurdie 1754
                        "and v.view_name='PROJECT WIDE' " +
1755
                        "and af.proj_id=rt.proj_id " +
1756
                        "and af.view_id=v.view_id " +
1757
                        "and mg.group_email_id=af.group_email_id " +
1758
                        "and u.user_id=mg.user_id"
1759
                );
7169 dpurdie 1760
        stmt0.setInt(1, baseline);
1761
 
6914 dpurdie 1762
        ResultSet rset0 = stmt0.executeQuery();
1763
        while( rset0.next() )
1764
        {
1765
            String email = rset0.getString("user_email");
1766
 
1767
            if ( email != null )
1768
            {
1769
                email = email.trim();
1770
                emailCollection.addAll( Arrays.asList(email.split("\\s*[,\\s]+\\s*")));
1771
            }
1772
        }
1773
 
1774
        rset0.close();
1775
        stmt0.close();
1776
 
1777
        //  Fetch the Release Specific email address
1778
        //  It may be comma separated
7169 dpurdie 1779
        CallableStatement stmt1 = mConnection.prepareCall("select owner_email from release_manager.release_tags rt where rt.rtag_id = ?" );
1780
        stmt1.setInt(1, baseline);
6914 dpurdie 1781
        ResultSet rset1 = stmt1.executeQuery();
1782
 
1783
        while( rset1.next() )
1784
        {
1785
            String email = rset1.getString("owner_email");
1786
 
1787
            if ( email != null )
1788
            {
1789
                email = email.trim();
1790
                emailCollection.addAll( Arrays.asList(email.split("\\s*[,\\s]+\\s*")));
1791
            }
1792
        }
1793
 
1794
        rset1.close();
1795
        stmt1.close();
1796
 
1797
        return emailCollection;
1798
    }
1799
 
1800
    /**	Clears the database entry of the build file
1801
     *  <br>The assumption is that the file has been collected from the database and stored for use
1802
     *  
1803
     *  <p>sets CURRENT_BUILD_FILES to NULL for the rcon_id
1804
     */
1805
    public void clearBuildFile(int rcon_id) throws SQLException, Exception
1806
    {
1807
        mLogger.debug("clearBuildFile");
1808
 
1809
        try
1810
        {
1811
            connect();
1812
 
1813
            CallableStatement stmt = mConnection.prepareCall(
1814
                    "update release_manager.run_level" +
1815
                    " set current_build_files=NULL" +
7169 dpurdie 1816
                    " where rcon_id=?"
6914 dpurdie 1817
                    );
7169 dpurdie 1818
            stmt.setInt(1, rcon_id);
6914 dpurdie 1819
            stmt.executeUpdate();
1820
            stmt.close();
1821
            commit();
1822
        }
1823
        catch ( SQLException e )
1824
        {
1825
            handleSQLException(e, "");
1826
        }
1827
        finally
1828
        {
1829
            // this block is executed regardless of what happens in the try block
1830
            // even if an exception is thrown
1831
            // ensure disconnect
1832
            disconnect();
1833
        }
1834
    }
1835
 
1836
    /** Stores a buildfile in the database so that all daemons can collect it
1837
     * updates the CURRENT_BUILD_FILES for the rtag_id
1838
     *      This will trigger the slave build cycle
1839
     * Also sets the pkg_id and pvId of the package being built
1840
     *      This is only used for display purposes in Release manager
1841
     * 
1842
     * @param rtag_id   - Target Release
1843
     * @param buildFile - buildfile content to be saved
1844
     */
1845
    public void publishBuildFile(int rtag_id, BuildFile buildFile) throws SQLException, Exception
1846
    {
7044 dpurdie 1847
        mLogger.debug("publishBuildFile publishing a build file of length {}", buildFile.content.length());
1848
        mLogger.debug("publishBuildFile publishing pkgId: {} pvid: {}", buildFile.mPkgId, buildFile.mPvId);
6914 dpurdie 1849
 
1850
        try
1851
        {
1852
            connect();
1853
 
1854
            if ( isRtagIdConfigured( rtag_id ) )
1855
            {
1856
                PreparedStatement stmt = mConnection.prepareStatement(
1857
                        "update release_manager.run_level " +
1858
                                "    set current_build_files=?,  " +
1859
                                "        current_pkg_id_being_built=?,"+
1860
                                "        current_pv_id=?," +
1861
                                "       last_build=sysdate" +
1862
                                "    WHERE rcon_id in (  " +
1863
                                "        select rl.rcon_id from release_manager.release_config rc,  " +
1864
                                "               release_manager.run_level rl  " +
1865
                                "        where rc.rtag_id=? and rl.rcon_id=rc.rcon_id )" );
1866
                stmt.setString(1, buildFile.content);
1867
 
1868
                if (buildFile.mPkgId ==  0) {
1869
                    stmt.setNull(2, Types.NUMERIC);
1870
                } else {
1871
                    stmt.setInt  (2, buildFile.mPkgId);
1872
                }
1873
 
1874
                if (buildFile.mPvId ==  0) {
1875
                    stmt.setNull(3, Types.NUMERIC);
1876
                } else {
1877
                    stmt.setInt  (3, buildFile.mPvId);
1878
                }
1879
 
1880
                stmt.setInt(4, rtag_id);
1881
 
1882
                stmt.executeUpdate();
1883
                stmt.close();
1884
                commit();
1885
            }
1886
        }
1887
        catch ( SQLException e )
1888
        {
1889
            handleSQLException(e, "");
1890
        }
1891
        catch ( Exception e )
1892
        {
1893
            // this catch and rethrow is historical
1894
            // problems were found using CallableStatement when updating a CLOB column with data > 4000 bytes
7044 dpurdie 1895
            mLogger.error("publishBuildFile caught Exception {}", e.getMessage());
6914 dpurdie 1896
            throw new Exception("publishBuildFile caught Exception " + e.getMessage());
1897
        }
1898
        finally
1899
        {
1900
            // this block is executed regardless of what happens in the try block
1901
            // even if an exception is thrown
1902
            // ensure disconnect
1903
            disconnect();
1904
        }
1905
    }
1906
 
1907
    /**only used in daemon mode
1908
     * <br>Query the Release Sequence Number for the specified Release, while ensuing that the machine
1909
     * is still a part of the current build set
1910
     * 
1911
     * @param   rtagId      Release Identifier
1912
     * @return  <0  - No longer a part of the Build Set
1913
     * <br>     >=0 - Release Sequence Number
1914
     * 
1915
     */
1916
    public int queryReleaseSeqNum(int rtagId, int rcon_id, String machine_hostname) throws SQLException, Exception
1917
    {
1918
        mLogger.debug("queryReleaseSeqNum");
1919
        int retVal = 0;
1920
 
1921
        if ( mUseDatabase )
1922
        {
1923
            try
1924
            {
1925
                connect();
1926
                mLogger.info("queryReleaseSeqNum queryReleaseSeqNum");
1927
                CallableStatement stmt = mConnection.prepareCall(
1928
                        "SELECT NVL(rl.pause,0) AS pause, " + 
7169 dpurdie 1929
                                "(select seqnum from release_modified where rtag_id = ?) as seqnum" +
6914 dpurdie 1930
                                " FROM run_level rl," +
1931
                                "  release_config rc," +
1932
                                "  BUILD_MACHINE_CONFIG bmc" +
7169 dpurdie 1933
                                " WHERE rl.rcon_id = ?" +
6914 dpurdie 1934
                                " AND rl.RCON_ID   = rc.RCON_ID" +
1935
                                " AND rc.BMCON_ID IS NOT NULL" +
1936
                                " AND rc.BMCON_ID = bmc.BMCON_ID" +
1937
                                " AND rc.DAEMON_MODE = 'M'" +
7169 dpurdie 1938
                                " AND UPPER(bmc.MACHINE_HOSTNAME) = UPPER(?)"
6914 dpurdie 1939
                                );
7169 dpurdie 1940
                stmt.setInt(1, rtagId);
1941
                stmt.setInt(2, rcon_id);
1942
                stmt.setString(3, machine_hostname);
1943
 
6914 dpurdie 1944
                ResultSet rset = stmt.executeQuery();
1945
                if( rset.next() )
1946
                {
1947
                    int pause = rset.getInt("pause");
1948
                    if (pause > 1)
1949
                        retVal = -2;
1950
                    else
1951
                        retVal = rset.getInt("seqnum");                        
1952
                }
1953
                else
1954
                {
1955
                    retVal = -1;
1956
                }
1957
 
1958
                rset.close();
1959
                stmt.close();
1960
            }
1961
            catch ( SQLException e )
1962
            {
1963
                handleSQLException(e, "");
1964
            }
1965
            finally
1966
            {
1967
                disconnect();
1968
            }
1969
        }
1970
 
7044 dpurdie 1971
        mLogger.warn("queryReleaseSeqNum returned {}", retVal);
6914 dpurdie 1972
        return retVal;
1973
    }
1974
 
1975
    /**
1976
     * Disable all the daemons for a specific release
1977
     *      Should only be done by the master
1978
     *      Used when master thread discovers that no build has occurred for a long time
1979
     *      
1980
     * @param rtag_id
1981
     * @throws SQLException
1982
     * @throws Exception
1983
     */
1984
    private void disableDaemons(final int rtag_id) throws SQLException, Exception
1985
    {
7176 dpurdie 1986
        mLogger.warn("disableDaemons: {}", rtag_id );
6914 dpurdie 1987
 
1988
        try
1989
        {
1990
            CallableStatement stmt1 = mConnection.prepareCall( "call PK_BUILDAPI.set_daemon_states(?,2)" );
1991
            stmt1.setInt( 1, rtag_id );
1992
            stmt1.executeUpdate();
1993
            stmt1.close();
1994
            commit();
1995
        }
1996
        catch ( SQLException e )
1997
        {
1998
            handleSQLException(e, "");
1999
        }
2000
    }
2001
 
2002
    /**Checks the existence of any valid daemon configuration for the Release
2003
     * 
2004
     * A valid configuration record has a release_config entry that is linked to
2005
     * a machine_configuration entry. ie: unlinked entries are not part of a configured set.
2006
     * 
2007
     * @param   rtag_id - Release Tag to test
2008
     * @return  True if the Release still has a configuration entry
2009
     */
2010
    private boolean isRtagIdConfigured(final int rtag_id) throws SQLException, Exception
2011
    {
2012
        mLogger.debug("isRtagIdConfigured");
2013
        boolean retVal = false;
2014
 
2015
        try
2016
        {
2017
            // check if the rcon_id is still configured
2018
            CallableStatement stmt = mConnection.prepareCall(
2019
                    "select rtag_id"
2020
                    + " from release_manager.release_config"
7169 dpurdie 2021
                    + " where rtag_id=?"
6914 dpurdie 2022
                    + " AND bmcon_id is not NULL");
7169 dpurdie 2023
            stmt.setInt(1, rtag_id);
6914 dpurdie 2024
            ResultSet rset = stmt.executeQuery();
2025
 
2026
            while( rset.next() )
2027
            {
2028
                retVal = true;
2029
            }
2030
 
2031
            rset.close();
2032
            stmt.close();
2033
        }
2034
        catch ( SQLException e )
2035
        {
2036
            handleSQLException(e, "");
2037
        }
7176 dpurdie 2038
        mLogger.debug("isRtagIdConfigured returning {}", retVal);
6914 dpurdie 2039
        return retVal;
2040
    }
2041
 
2042
    /**queries the RUN_LEVEL table for daemon to determine if the daemon has been paused
2043
     * or disabled.
2044
     * 
2045
     * Used as a part of allowedToProceed()
2046
     * 
2047
     * Handles the following conditions
2048
     *  Daemon has be de-configured - Returns TRUE
2049
     *  Daemon has been paused - Returns FALSE
2050
     *  Daemon has been disabled - Returns TRUE
2051
     *  Daemon has been set to run - Returns TRUE 
2052
     * 
2053
     * @param   rcon_id Connection identifier
2054
     * @returns False: Build agent has been commanded to PAUSE
2055
     *      <br>True: All other conditions
2056
     * 
2057
     * @exception SQLException
2058
     * @exception Exception
2059
     */
2060
    public boolean queryDirectedRunLevel(final int rcon_id) throws SQLException, Exception
2061
    {
7044 dpurdie 2062
        mLogger.debug("queryDirectedRunLevel {}", rcon_id);
6914 dpurdie 2063
        boolean retVal = true;
2064
 
2065
        if ( mUseDatabase )
2066
        {
2067
            try
2068
            {
2069
                CallableStatement stmt = mConnection.prepareCall(
2070
                        "select NVL(rl.pause,0) as pause" +
2071
                        " from release_manager.run_level rl, release_manager.release_config rc "+
7169 dpurdie 2072
                        " where rl.rcon_id=?" +
6914 dpurdie 2073
                        " and rl.RCON_ID = rc.RCON_ID" +
2074
                        " and rc.BMCON_ID is not NULL"
2075
                        );
7169 dpurdie 2076
                stmt.setInt(1, rcon_id);
6914 dpurdie 2077
                ResultSet rset = stmt.executeQuery();
2078
                int rsetSize = 0;
2079
 
2080
                while( rset.next() )
2081
                {
2082
                    rsetSize++;
2083
 
2084
                    //
2085
                    //  Pause: null -> 0 == Run
2086
                    //         1         == Pause
2087
                    //         2         == Disabled
2088
                    //
2089
                    int pause = rset.getInt("pause");
2090
                    if ( pause == 1) {
2091
                        retVal = false;
2092
                    }
2093
                }
2094
 
2095
                rset.close();
2096
                stmt.close();
2097
 
2098
                if ( rsetSize > 1 )
2099
                {
7033 dpurdie 2100
                    mLogger.error("queryDirectedRunLevel rsetSize > 1");
6914 dpurdie 2101
                    // show stopper
2102
                    throw new Exception("queryDirectedRunLevel rsetSize > 1");
2103
                }
2104
            }
2105
            catch ( SQLException e )
2106
            {
2107
                handleSQLException(e, "");
2108
            }
2109
        }
2110
 
7176 dpurdie 2111
        mLogger.debug("queryDirectedRunLevel returning {}", retVal);
6914 dpurdie 2112
        return retVal;
2113
    }
2114
 
2115
    /**
2116
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG tables using the rcon_id primary key, rtag_id, machine_hostname, daemon_mode
2117
     * <p>Return true if the query contains a result set containing one row
2118
     *  (indicating the rcon_id is still configured and its configuration is unchanged, aside from the gbe_buildfilter)
2119
     *  the gbe_buildfilter is queried prior to usage
2120
     * 
2121
     *  <p>Used to determine if this daemon should be allowed to continue running
2122
     *  or if it should be terminated
2123
     *  
2124
     * <br>Overridden in ReleaseManagerUtf 
2125
     * 
2126
     * @param rtag_id          The rtag_id of the machine to examine
2127
     * @param rcon_id          The rcond_id of the machine to examine
2128
     * @param machine_hostname The hostname of the machine to examine
2129
     * @param daemon_mode      The daemon mode of the machine to examine
2130
     * @param threadStartTime  The time that the thread started
2131
     * 
2132
     * @return True: The machine is a part of the current build set
2133
     *         False: The machine is not a part of the current build set
2134
     * @exception SQLException
2135
     * @exception Exception
2136
     */
2137
    public boolean queryReleaseConfig(final int rtag_id, final int rcon_id,final String machine_hostname, final char daemon_mode, final long threadStartTime) throws SQLException, Exception
2138
    {
2139
        mLogger.debug("queryReleaseConfig 1");
2140
        boolean retVal = false;
2141
 
2142
        try
2143
        {
2144
            String sql = 
2145
                    "select rl.pause," +
2146
                    "       rt.build_age," +
2147
                    "       TRUNC((SYSDATE-rl.last_build) ) as last_build_days" +
2148
                    "   from release_manager.release_config rc," +
2149
                    "        release_manager.release_tags rt," +
2150
                    "        release_manager.run_level rl," +
2151
                    "        release_manager.build_machine_config bc" +
2152
                    "   where rc.rtag_id=?" +
2153
                    "     and rc.rcon_id=?" +
2154
                    "     and rc.bmcon_id is not NULL" +
2155
                    "     and rc.bmcon_id = bc.bmcon_id" +
2156
                    "     and bc.machine_hostname=?" +
2157
                    "     and rc.daemon_mode=?" +
2158
                    "     and rl.rcon_id=rc.rcon_id" +
2159
                    "     and rt.rtag_id=rc.rtag_id" +
2160
                    "     and (rt.official = 'N' or rt.official='R' or rt.official='C')";
2161
 
2162
            CallableStatement stmt = mConnection.prepareCall( sql );
2163
            stmt.setFetchSize(10);
2164
            stmt.setInt(1, rtag_id);
2165
            stmt.setInt(2, rcon_id);
2166
            stmt.setString(3, machine_hostname);
2167
            stmt.setString(4, Character.toString(daemon_mode));
7023 dpurdie 2168
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 1");
6914 dpurdie 2169
            int rsetSize = 0;
2170
 
2171
            while( rset.next() )
2172
            {
2173
                rsetSize++;
2174
 
2175
                //
2176
                //  Pause: null -> 0 == Run
2177
                //         1         == Pause
2178
                //         2         == Disabled
2179
                //
7023 dpurdie 2180
                int pause = rset.getInt("pause",0);
2181
                int build_age = rset.getInt("build_age", 0);
2182
                int days_since_last_build = rset.getInt("last_build_days", 0);
6914 dpurdie 2183
 
2184
                //
2185
                //  Determine if we should disable the daemons on this release because they have not been
2186
                //  used in a long while.
2187
                //
2188
                //  Only Master makes the decision
2189
                //  If build_age is zero - then the daemon does not get aged out
2190
                //  If the days since last build > build_age, then we will shut down
2191
                //      Allow one days grace - will show up IN RM for a day
2192
                //  Allow the thread to run for x hours before shutting it down
2193
                //      Handles case where daemon has just been started/restarted
2194
                //
2195
                if ( daemon_mode == 'M' &&  build_age > 0 && days_since_last_build > (build_age + 1) )
2196
                {
2197
                    long upTimeSecs = (System.currentTimeMillis() - threadStartTime)/1000;
7176 dpurdie 2198
                    mLogger.warn("queryReleaseConfig 1: {},{},{},{},{},{},{}",rtag_id, rcon_id, daemon_mode, pause, build_age, days_since_last_build, upTimeSecs );
6914 dpurdie 2199
                    if ( upTimeSecs > mPostponeShutdown)
2200
                    {
2201
                        disableDaemons(rtag_id);
2202
                        pause = 2;
2203
                    }
2204
                    else
2205
                    {
7176 dpurdie 2206
                        mLogger.warn("queryReleaseConfig 1: Shutdown Postponed"  );    
6914 dpurdie 2207
                    }
2208
                }
2209
 
7044 dpurdie 2210
                mLogger.info("queryReleaseConfig 1: {},{},{},{},{},{}",rtag_id, rcon_id, daemon_mode, pause, build_age, days_since_last_build  );
6914 dpurdie 2211
 
2212
                if ( pause <= 1 )
2213
                {
2214
                    retVal = true;
2215
                }
2216
            }
2217
 
2218
            rset.close();
2219
            stmt.close();
2220
 
2221
            if ( rsetSize > 1 )
2222
            {
7033 dpurdie 2223
                mLogger.error("queryReleaseConfig 1 rsetSize > 1");
6914 dpurdie 2224
                // show stopper
2225
                throw new Exception("queryReleaseConfig 1 rsetSize > 1");
2226
            }
2227
        }
2228
        catch ( SQLException e )
2229
        {
2230
            handleSQLException(e, ":1");
2231
        }
2232
 
7176 dpurdie 2233
        mLogger.debug("queryReleaseConfig 1 returning {}", retVal);
6914 dpurdie 2234
        return retVal;
2235
    }
2236
 
2237
    /**removes all elements from the mReleaseConfigCollection
2238
     * handles database connection and disconnection
2239
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG tables using the rtag_id 
2240
     *  
2241
     * populates the mReleaseConfigCollection with the query result set
2242
     * partially implements the sequence diagrams coordinate slave threads generate build files 
2243
     *  
2244
     * Used by Master Thread to determine the build machines that will be a part 
2245
     * of the Slave-Sync process.
2246
     * 
2247
     *  Only called when a database connection has been established
2248
     */
2249
    public void queryReleaseConfig(final int rtag_id) throws SQLException, Exception
2250
    {
2251
        mLogger.debug("queryReleaseConfig 2");
2252
        mReleaseConfigCollection.resetData();
2253
 
2254
        try
2255
        {
2256
            //connect();
2257
 
2258
            CallableStatement stmt = mConnection.prepareCall(
2259
                    " select rc.rcon_id,"+
2260
                    "        rc.daemon_mode,"+
2261
                    "        rl.pause,"+
2262
                    "        bc.machine_hostname,"+
2263
                    "        rc.gbe_buildfilter,"+
2264
                    "        mt.gbe_value,"+
2265
                    "        bm.bm_name" +
2266
                    "    from release_manager.release_config rc, " +
2267
                    "         release_manager.run_level rl, " +
2268
                    "         release_manager.build_machine_config bc, " +
2269
                    "         release_manager.gbe_machtype mt," +
2270
                    "         release_manager.build_machines bm" +
2271
                    "    where   rc.rtag_id=?" +
2272
                    "        and rl.rcon_id=rc.rcon_id " +
2273
                    "        and rc.bmcon_id is not NULL" +
2274
                    "        and rc.bmcon_id = bc.bmcon_id" +
2275
                    "        and mt.gbe_id=bc.gbe_id" +
2276
                    "        and mt.bm_id=bm.bm_id"
2277
                    );
2278
            stmt.setFetchSize(10);
2279
            stmt.setInt(1, rtag_id);
7023 dpurdie 2280
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 2");
6914 dpurdie 2281
 
2282
            while( rset.next() )
2283
            {
7023 dpurdie 2284
                int rcon_id = rset.mustGetInt("rcon_id");
2285
 
6914 dpurdie 2286
                char dm = 'S';          
7023 dpurdie 2287
                String daemon_mode = rset.getString("daemon_mode","S");
2288
 
7176 dpurdie 2289
                mLogger.debug("queryReleaseConfig 2 daemon_mode '{}'", daemon_mode);
6914 dpurdie 2290
 
7023 dpurdie 2291
                if ( daemon_mode.compareTo("M") == 0 )
6914 dpurdie 2292
                {
7023 dpurdie 2293
                    dm = 'M';
6914 dpurdie 2294
                }
2295
 
7023 dpurdie 2296
                String machine_hostname = rset.mustGetString("machine_hostname");
2297
                String gbe_buildfilter = rset.getString("gbe_buildfilter","");
2298
                String gbe_machtype = rset.mustGetString("gbe_value");
2299
                String gbe_machclass = rset.mustGetString("bm_name");
6914 dpurdie 2300
                //
2301
                //  Pause: null -> 0 == Run
2302
                //         1         == Pause
2303
                //         2         == Disabled
2304
                //
7023 dpurdie 2305
                int pause = rset.getInt("pause",0);
6914 dpurdie 2306
                mLogger.info("queryReleaseConfig 2: " + rtag_id + ", " + rcon_id + ", "+ dm + ", " + pause + 
2307
                        ", " + machine_hostname + ", " + gbe_buildfilter + ", " + gbe_machtype + ", + " + gbe_machclass );
2308
 
2309
                //
2310
                // Daemon Mode : Do not include build daemons that are disabled
2311
                // Escrow Mode : Include all machines
2312
                //
2313
                if ( pause <= 1 ||  ! mDaemon )
2314
                {
2315
                    ReleaseConfig releaseConfig = new ReleaseConfig( rtag_id, rcon_id, dm, machine_hostname, gbe_buildfilter, gbe_machtype, gbe_machclass);
2316
                    mReleaseConfigCollection.add(releaseConfig);
2317
                }
2318
            }
2319
 
2320
 
2321
            rset.close();
2322
            stmt.close();
2323
        }
2324
        catch ( SQLException e )
2325
        {
2326
            handleSQLException(e, ":2");
2327
        }
2328
        finally
2329
        {
2330
            // this block is executed regardless of what happens in the try block
2331
            // even if an exception is thrown
2332
            // ensure disconnect
2333
            //disconnect();
2334
        }
2335
    }
2336
 
2337
    /**removes all elements from the mReleaseConfigCollection
2338
     * handles database connection and disconnection
2339
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG table using the machine_hostname
2340
     * populates the mReleaseConfigCollection with the query result set
2341
     * partially implements the sequence diagram spawn thread 
2342
     *  
2343
     * Used by the BuildDaemon thread to determine daemons to start and stop
2344
     */
2345
    public void queryReleaseConfig(final String hostname) throws SQLException, Exception
2346
    {
7044 dpurdie 2347
        mLogger.debug("queryReleaseConfig 3 {}", hostname);
6914 dpurdie 2348
        mReleaseConfigCollection.resetData();
2349
 
2350
        try
2351
        {
2352
            connect();
2353
            CallableStatement stmt = mConnection.prepareCall(
2354
                    "select rc.rtag_id,"+
2355
                    "       rc.rcon_id,"+
2356
                    "       rc.daemon_mode,"+
2357
                    "       rl.pause,"+
2358
                    "       bc.machine_hostname,"+
2359
                    "       rc.gbe_buildfilter,"+
2360
                    "       mt.gbe_value,"+
2361
                    "       bm.bm_name" +
2362
                    "  from release_manager.release_config rc," +
2363
                    "       release_manager.release_tags rt," +
2364
                    "       release_manager.run_level rl," +
2365
                    "       release_manager.build_machine_config bc," +
2366
                    "       release_manager.gbe_machtype mt," +
2367
                    "       release_manager.build_machines bm " +
2368
                    "    where bc.machine_hostname=?" +
2369
                    "      and rt.rtag_id=rc.rtag_id" +
2370
                    "      and rl.rcon_id=rc.rcon_id" +
2371
                    "      and rc.bmcon_id is not NULL" +
2372
                    "      and bc.bmcon_id=rc.bmcon_id" +
2373
                    "      and mt.gbe_id=bc.gbe_id" +
2374
                    "      and mt.bm_id=bm.bm_id" +
2375
                    "      and (rt.official = 'N' or rt.official='R' or rt.official='C')"
2376
                    );
2377
 
2378
            stmt.setFetchSize(20);
2379
            stmt.setString(1, hostname);
7023 dpurdie 2380
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 3");
6914 dpurdie 2381
 
2382
            while( rset.next() )
2383
            {
7023 dpurdie 2384
                int rtag_id = rset.mustGetKeyInt("rtag_id");
2385
                int rcon_id = rset.mustGetInt("rcon_id");
6914 dpurdie 2386
 
2387
                char dm = 'S';          
7023 dpurdie 2388
                String daemon_mode = rset.getString("daemon_mode", "S");
6914 dpurdie 2389
 
7176 dpurdie 2390
                mLogger.debug("queryReleaseConfig 3 daemon_mode '{}'", daemon_mode);
6914 dpurdie 2391
 
7023 dpurdie 2392
                if ( daemon_mode.compareTo("M") == 0 )
6914 dpurdie 2393
                {
7023 dpurdie 2394
                    dm = 'M';
6914 dpurdie 2395
                }
2396
 
7023 dpurdie 2397
                String machine_hostname = rset.mustGetString("machine_hostname");
2398
                String gbe_buildfilter = rset.getString("gbe_buildfilter",null);
2399
                String gbe_machtype = rset.mustGetString("gbe_value");
2400
                String gbe_machclass = rset.mustGetString("bm_name");
2401
 
6914 dpurdie 2402
                //
2403
                //  Pause: null -> 0 == Run
2404
                //         1         == Pause
2405
                //         2         == Disabled
2406
                //
7023 dpurdie 2407
                int pause = rset.getInt("pause",0);
2408
 
6914 dpurdie 2409
                mLogger.info("queryReleaseConfig 3: " + rtag_id + ", " + rcon_id + ", "+ dm + ", " + pause + 
2410
                        ", " + machine_hostname + ", " + gbe_buildfilter + ", " + gbe_machtype + ", + " + gbe_machclass );
2411
 
2412
                //
2413
                // Do not include build daemons that are disabled
2414
                // Only those that are running or paused
2415
                //
2416
                if ( pause <= 1 )
2417
                {
2418
                    ReleaseConfig releaseConfig = new ReleaseConfig( rtag_id, rcon_id, dm, machine_hostname, gbe_buildfilter, gbe_machtype, gbe_machclass);
2419
                    mReleaseConfigCollection.add(releaseConfig);
2420
                }
2421
            }
2422
 
2423
            rset.close();
2424
            stmt.close();
2425
        }
2426
        catch ( SQLException e )
2427
        {
2428
            handleSQLException(e, ":3");
2429
        }
2430
        finally
2431
        {
2432
            // this block is executed regardless of what happens in the try block
2433
            // even if an exception is thrown
2434
            // ensure disconnect
2435
            disconnect();
2436
        }
2437
 
2438
    }
2439
 
2440
    /** Check that the build set has exactly one master
2441
     *  
2442
     *  Ignores entries that are disabled
2443
     *  Ignore entries that have been 'unlinked' - they have no active machine configuration
2444
     *
2445
     *   @param rtag_id - Release Tag
2446
     *  
2447
     *  Used by the Master and Slave Daemons 
2448
     *  Overridden in ReleaseManagerUtf 
2449
     */
2450
    public int queryMasterCount(final int rtag_id) throws SQLException, Exception
2451
    {
7044 dpurdie 2452
        mLogger.debug("queryMasterCount rtag_id {}", rtag_id);
6914 dpurdie 2453
 
2454
        int masterCount = 0;
2455
        try
2456
        {
2457
            connect();
2458
            CallableStatement stmt = mConnection.prepareCall(
2459
                            "SELECT COUNT (rc.daemon_mode) as masterCount" +
2460
                            " FROM release_manager.release_config rc, release_manager.run_level rl" +
7169 dpurdie 2461
                            " WHERE rc.rtag_id = ?" +
6914 dpurdie 2462
                            " AND rl.RCON_ID = rc.RCON_ID" +
2463
                            " AND   rc.bmcon_id is not NULL" +
2464
                            " AND NVL(rl.PAUSE,0) != 2" +
2465
                            " GROUP BY rc.daemon_mode" +
2466
                            " HAVING rc.daemon_mode = 'M'" );
7169 dpurdie 2467
            stmt.setInt(1, rtag_id);
6914 dpurdie 2468
            ResultSet rset = stmt.executeQuery();
2469
 
2470
            if ( rset.next() )
2471
            {
2472
                masterCount = rset.getInt("masterCount");
2473
            }
2474
 
2475
            rset.close();
2476
            stmt.close();
2477
        }
2478
        catch ( SQLException e )
2479
        {
2480
            handleSQLException(e, "");
2481
        }
2482
        finally
2483
        {
2484
            // this block is executed regardless of what happens in the try block
2485
            // even if an exception is thrown
2486
            // ensure disconnect
2487
            disconnect();
2488
        }
2489
 
2490
        return masterCount;
2491
    }
2492
 
2493
    /**
2494
     * Determine an array of machines for which there are active build requests
2495
     * Used to notify slave machines of a pending build request
2496
     * 
2497
     *  
2498
     * @param mHostname - Identifies the build machine
2499
     * @param rconIdList - Comma separated list of RCON_IDs that we are interested in
2500
     * @return An array of Integers, each being the rcon_id of a machine that has an active build
2501
     * @throws Exception 
2502
     */
2503
    public ArrayList<Integer> queryActivatedBuilds(String mHostname, String rconIdList) throws Exception {
2504
 
2505
        ArrayList<Integer> rv = new ArrayList<Integer>();
2506
        try
2507
        {
2508
            connect();
2509
            PreparedStatement stmt = mConnection.prepareStatement(
2510
                    "SELECT rl.rcon_id, rc.RTAG_ID" +
2511
                    " FROM run_level rl, release_config rc, release_tags rt" +
2512
                    " WHERE  rt.rtag_id = rc.RTAG_ID" +
7176 dpurdie 2513
                    " AND UPPER(rc.daemon_hostname) = UPPER(?)" +
6914 dpurdie 2514
                    " AND rc.DAEMON_MODE != 'M'" +
2515
                    " AND rc.RCON_ID = rl.rcon_id" +
2516
                    " AND CURRENT_BUILD_FILES IS NOT NULL" +
2517
                    " AND rl.pause is null" +
7180 dpurdie 2518
                    " AND rl.rcon_id in (" +
2519
                        "select regexp_substr(?,'[^,]+', 1, level) from dual connect by regexp_substr(?, '[^,]+', 1, level) is not null" +
2520
                    ")"
6914 dpurdie 2521
                    );
7176 dpurdie 2522
 
7180 dpurdie 2523
            //  Need some trikery to allow the use of a 'string' in a preparedStatement with an 'in' clause
2524
            //  jdbc does not allow a simple 'select * from ... where aa in (?)
2525
            //  So we need to split a comma separated string into something that can be used.
2526
            //  Thus the 'select regexp ... '
7176 dpurdie 2527
            stmt.setString(1, mHostname);
2528
            stmt.setString(2, rconIdList);
7180 dpurdie 2529
            stmt.setString(3, rconIdList);
6914 dpurdie 2530
 
2531
            ResultSet rset = stmt.executeQuery();
2532
 
2533
            while (rset.next()) {
2534
                Integer ii = rset.getInt("rcon_id");
2535
                rv.add(ii);
2536
            }
2537
 
2538
            rset.close();
2539
            stmt.close();
2540
        }
2541
        catch ( SQLException e )
2542
        {
2543
            handleSQLException(e, "");
2544
        }
2545
        finally
2546
        {
2547
            // this block is executed regardless of what happens in the try block
2548
            // even if an exception is thrown
2549
            // ensure disconnect
2550
            disconnect();
2551
        }
2552
        return rv;
2553
    }
2554
 
7044 dpurdie 2555
    /**
7088 dpurdie 2556
     * Extract all package-version information for released packages
2557
     * Used in both Escrow and non-Escrow modes
7044 dpurdie 2558
     * 
2559
     * @param   rippleEngine        - Instance to use
2560
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2561
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
6914 dpurdie 2562
     *  
2563
     * Overridden in ReleaseManagerUtf
2564
     *  
2565
     */
7186 dpurdie 2566
    protected void queryPackageVersions(RippleEngine rippleEngine, PackageCollection packageCollection, int baseline) throws SQLException, Exception
6914 dpurdie 2567
    {
2568
        Phase phase = new Phase("rmData");
7044 dpurdie 2569
        mLogger.debug("queryPackageVersions {}", mDaemon);
7137 dpurdie 2570
 
6914 dpurdie 2571
        try
2572
        {
2573
            if (mDaemon)
2574
            {
7082 dpurdie 2575
                // Get package information on ALL released packages within the release of interest
6914 dpurdie 2576
                //
2577
                mLogger.debug("queryPackageVersions: stmt8");
2578
                phase.setPhase("getAllPkgs1");
2579
                PreparedStatement stmt8 = mConnection.prepareStatement(
2580
                        "SELECT rc.pv_id," +
7046 dpurdie 2581
                                " p.pkg_id," +
2582
                                " p.pkg_name," +
2583
                                " pv.pkg_version," +
2584
                                " pv.v_ext," +
2585
                                " pv.ripple_field," +
2586
                                " pv.major_limit," +
2587
                                " pv.minor_limit," +
2588
                                " pv.patch_limit," +
2589
                                " pv.build_number_limit," +
2590
                                " pv.build_type," +
2591
                                " rc.sdktag_id," +
2592
                                " rc.ripple_stop," +
2593
                                " peg.pv_id as pegged," +
2594
                                " release_manager.PK_RMAPI.return_vcs_tag(rc.pv_id) AS vcsTag," +
2595
                                " pv.build_time" +
6914 dpurdie 2596
                                " FROM release_manager.release_content rc," +
2597
                                "  release_manager.package_versions pv," +
2598
                                "  release_manager.packages p," +
2599
                                "  release_manager.pegged_versions peg" +
7176 dpurdie 2600
                                " WHERE rc.rtag_id=?" +
6914 dpurdie 2601
                                " AND pv.pv_id    = rc.pv_id" +
2602
                                " AND p.pkg_id    = pv.pkg_id" +
2603
                                " AND peg.rtag_id(+) = rc.rtag_id" +
2604
                                " AND peg.pv_id(+) = rc.pv_id" +
2605
                                " ORDER BY rc.pv_id"
2606
                        );
7176 dpurdie 2607
                stmt8.setInt(1, baseline);
6914 dpurdie 2608
                mLogger.debug("queryPackageVersions: stmt8 Prepared");
2609
                stmt8.setFetchSize(1000);
7023 dpurdie 2610
                RmResultSet rset8 = new RmResultSet(stmt8.executeQuery(), "queryPackageVersions rset8");
6914 dpurdie 2611
                mLogger.debug("queryPackageVersions: stmt8 Query Done");
2612
 
2613
                while( rset8.next() )
2614
                {
7023 dpurdie 2615
                    int pv_id = rset8.mustGetKeyInt("pv_id");
2616
                    int pkg_id = rset8.mustGetInt("pkg_id");
2617
                    String pkg_name = rset8.mustGetString("pkg_name");
2618
                    String pkg_version = rset8.mustGetString("pkg_version");
2619
                    String v_ext = rset8.getString("v_ext", "");
2620
                    String ripple_field = rset8.getString("ripple_field", "b");
2621
                    int major_limit = rset8.getInt("major_limit",0);
2622
                    int minor_limit = rset8.getInt("minor_limit", 0);
2623
                    int patch_limit = rset8.getInt("patch_limit",0);
2624
                    int build_number_limit = rset8.getInt("build_number_limit", 0);
2625
                    String vcs_tag = rset8.getString("vcsTag","");
2626
                    int isAnSdk = rset8.getInt("sdktag_id",0); 
2627
                    int isPegged = rset8.getInt("pegged",0);
2628
                    String buildType = rset8.getString("build_type", null);
6914 dpurdie 2629
                    boolean isBuildable = ( buildType != null ) && (buildType.equals("A") || buildType.equals("Y") );
7046 dpurdie 2630
                    int buildTime = rset8.getInt("build_time", 60);
6914 dpurdie 2631
 
7023 dpurdie 2632
                    String rippleStopData = rset8.getString("ripple_stop","n");
2633
                    char rippleStop = rippleStopData.charAt(0);
6914 dpurdie 2634
 
2635
                    Package p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
2636
                    p.mMajorLimit = major_limit;
2637
                    p.mMinorLimit = minor_limit;
2638
                    p.mPatchLimit = patch_limit;
2639
                    p.mBuildLimit = build_number_limit;
2640
                    p.mIsSdk = isAnSdk > 0;
2641
                    p.mIsPegged = isPegged > 0;
2642
                    p.mIsBuildable = isBuildable;
2643
                    p.mRippleStop = rippleStop;
7046 dpurdie 2644
                    p.mBuildTime = buildTime;
6914 dpurdie 2645
 
2646
                    //  If this package is to be replaced by a planned package then
2647
                    //  insert some of the current packages attributes
2648
                    //  Otherwise, add the the package to the package collection
7163 dpurdie 2649
                    //  TODO - Not sure this code is in use anymore
7082 dpurdie 2650
 
7186 dpurdie 2651
                    Package plannedPackage = packageCollection.contains(p.mAlias);
2652
                    if ( plannedPackage == null )
6914 dpurdie 2653
                    {
7176 dpurdie 2654
                        mLogger.debug("queryPackageVersions rset8 no planned package {}", pv_id);
6914 dpurdie 2655
                        packageCollection.add(p);
2656
                    }
2657
                    else
2658
                    {
2659
                        //  Copy these flags from the package that will be replaced
2660
                        //      Should not be able to replace a package provided by an SDK
2661
                        plannedPackage.mIsSdk = p.mIsSdk;
2662
 
2663
                        // A pegged package can be replaced with a directly built package
2664
                        // plannedPackage.mIsPegged = p.mIsPegged;
2665
                    }
2666
                }
2667
 
2668
                mLogger.debug("queryPackageVersions: stmt8 processing complete");
2669
                rset8.close();
2670
                stmt8.close();
2671
 
2672
                // get released package dependency info
2673
                // 
2674
                mLogger.debug("queryPackageVersions: stmt9");
2675
                phase.setPhase("getAllPkgs2");
2676
                PreparedStatement stmt9 = mConnection.prepareStatement(
7023 dpurdie 2677
                        "select rc.pv_id as pv_id, dpv.pv_id as dpv_id, p.pkg_name, dpv.v_ext" +
6914 dpurdie 2678
                                " from release_manager.release_content rc," +
2679
                                "      release_manager.package_versions pv," + 
2680
                                "      release_manager.package_dependencies pd,"+
2681
                                "      release_manager.package_versions dpv,"+
2682
                                "      release_manager.packages p" +
7176 dpurdie 2683
                                " where rc.rtag_id=?" + 
6914 dpurdie 2684
                                "  and pv.pv_id = rc.pv_id" +
2685
                                "  and pd.pv_id=pv.pv_id" +
2686
                                "  and dpv.pv_id=pd.dpv_id" +
2687
                                "  and p.pkg_id=dpv.pkg_id" +
2688
                                " order by rc.pv_id"
2689
                        );
2690
                mLogger.debug("queryPackageVersions: stmt9 prepared");
7176 dpurdie 2691
                stmt9.setInt(1, baseline);
6914 dpurdie 2692
                stmt9.setFetchSize(1000);
7023 dpurdie 2693
                RmResultSet rset9 = new RmResultSet(stmt9.executeQuery(), "queryPackageVersions rset9");
6914 dpurdie 2694
                mLogger.debug("queryPackageVersions: stmt9 query done");
2695
 
2696
                while( rset9.next() )
2697
                {
7023 dpurdie 2698
                    int pv_id = rset9.mustGetKeyInt("pv_id");
2699
                    int dpv_id = rset9.mustGetInt("dpv_id");
2700
                    String pkg_name = rset9.mustGetString("pkg_name");
2701
                    String v_ext = rset9.getString("v_ext","");
6914 dpurdie 2702
 
7186 dpurdie 2703
                    Package p = packageCollection.contains(pv_id);
2704
                    if ( p != null )
6914 dpurdie 2705
                    {
7163 dpurdie 2706
                        p.addDependency(pkg_name + v_ext, dpv_id );
6914 dpurdie 2707
                    }
7082 dpurdie 2708
 
6914 dpurdie 2709
                }
2710
                mLogger.debug("queryPackageVersions: stmt9 processing complete");
2711
 
2712
                rset9.close();
2713
                stmt9.close();
2714
 
2715
                // get released package build info
2716
                mLogger.debug("queryPackageVersions: stmt10");
2717
                phase.setPhase("getAllPkgs3");
2718
                PreparedStatement stmt10 = mConnection.prepareStatement(
2719
                        "select rc.pv_id, bm.bm_name, bsa.bsa_name " +
2720
                                "from release_manager.release_content rc," +
2721
                                "     release_manager.package_versions pv," +
2722
                                "     release_manager.package_build_info pbi," +
2723
                                "     release_manager.build_machines bm," +
2724
                                "     release_manager.build_standards_addendum bsa " +
2725
                                "where rc.rtag_id=?" + 
2726
                                "     and pv.pv_id = rc.pv_id" +
2727
                                "     and pbi.pv_id=pv.pv_id" +
2728
                                "     and bm.bm_id=pbi.bm_id" +
2729
                                "     and bsa.bsa_id=pbi.bsa_id " +
2730
                                "order by rc.pv_id"
2731
                        );
2732
                stmt10.setFetchSize(1000);
2733
                stmt10.setInt(1, baseline);
7023 dpurdie 2734
                RmResultSet rset10 = new RmResultSet(stmt10.executeQuery(), "queryPackageVersions rset10");
6914 dpurdie 2735
 
2736
                while( rset10.next() )
2737
                {
7023 dpurdie 2738
                    int pv_id = rset10.mustGetKeyInt("pv_id");
2739
                    String bm_name = rset10.mustGetString("bm_name");
2740
                    String bsa_name = rset10.mustGetString("bsa_name");
6914 dpurdie 2741
 
7186 dpurdie 2742
                    Package p = packageCollection.contains(pv_id);
2743
                    if ( p != null )
6914 dpurdie 2744
                    {
2745
                        BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
2746
                        if ( bs.supportedBuildStandard() )
2747
                        {
2748
                            p.mBuildStandardCollection.add(bs);
2749
                        }
2750
                    }
2751
                }
2752
 
2753
                rset10.close();
2754
                stmt10.close();
2755
 
2756
                // get released package unit test info
2757
                mLogger.debug("queryPackageVersions: stmt11");
2758
                phase.setPhase("getAllPkgs4");
2759
                PreparedStatement stmt11 = mConnection.prepareStatement(
2760
                        "select rc.pv_id, tt.test_type_name " +
2761
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.unit_tests ut, release_manager.test_types tt " +
7176 dpurdie 2762
                                "where rc.rtag_id=?" +
6914 dpurdie 2763
                                " and pv.pv_id = rc.pv_id and ut.pv_id=pv.pv_id and tt.test_type_id=ut.test_types_fk " +
2764
                                "order by rc.pv_id"
2765
                        );
7176 dpurdie 2766
                stmt11.setInt(1, baseline);
6914 dpurdie 2767
                stmt11.setFetchSize(1000);
7023 dpurdie 2768
                RmResultSet rset11 = new RmResultSet(stmt11.executeQuery(), "queryPackageVersions rset11");
6914 dpurdie 2769
 
2770
                while( rset11.next() )
2771
                {
7023 dpurdie 2772
                    int pv_id = rset11.mustGetKeyInt("pv_id");
7082 dpurdie 2773
                    String test_type_name = rset11.mustGetString("test_type_name");
7186 dpurdie 2774
                    Package p = packageCollection.contains(pv_id);
2775
                    if ( p != null )
6914 dpurdie 2776
                    {
2777
                        if ( test_type_name.compareTo("Autobuild UTF") == 0 )
2778
                        {
2779
                            p.mHasAutomatedUnitTests = true;
2780
                        }
2781
                    }
2782
                }
2783
 
2784
                rset11.close();
2785
                stmt11.close();
2786
 
2787
                // get released package build failure info...
2788
                // view based
2789
                mLogger.debug("queryPackageVersions: stmt12");
2790
                phase.setPhase("getAllPkgs5");
2791
                PreparedStatement stmt12 = mConnection.prepareStatement(
2792
                        "SELECT rc.pv_id," +
2793
                        "  u.user_email" +
2794
                        " FROM release_manager.release_content rc," +
2795
                        "  release_manager.release_tags rt," +
2796
                        "  release_manager.package_versions pv," +
2797
                        "  release_manager.autobuild_failure af," +
2798
                        "  release_manager.members_group mg," +
2799
                        "  release_manager.users u" +
7176 dpurdie 2800
                        " WHERE rc.rtag_id     = ?" +
6914 dpurdie 2801
                        " AND rt.rtag_id       = rc.rtag_id" +
2802
                        " AND pv.pv_id         = rc.pv_id" +
2803
                        " AND af.view_id       = rc.base_view_id" +
2804
                        " AND mg.group_email_id= af.group_email_id" +
2805
                        " AND u.user_id        = mg.user_id" +
2806
                        " AND af.proj_id       = rt.proj_id" +
2807
                        " ORDER BY rc.pv_id"
2808
                        );
7176 dpurdie 2809
                stmt12.setInt(1, baseline);
6914 dpurdie 2810
                stmt12.setFetchSize(1000);
7023 dpurdie 2811
                RmResultSet rset12 = new RmResultSet(stmt12.executeQuery(), "queryPackageVersions rset12");
6914 dpurdie 2812
 
2813
                while( rset12.next() )
2814
                {
7023 dpurdie 2815
                    int pv_id = rset12.mustGetKeyInt("pv_id");
7082 dpurdie 2816
                    String user_email = rset12.getString("user_email",null);
7186 dpurdie 2817
                    Package p = packageCollection.contains(pv_id);
2818
                    if ( p != null )
6914 dpurdie 2819
                    {
7088 dpurdie 2820
                        p.addEmail(user_email);
6914 dpurdie 2821
                    }
2822
                }
2823
 
2824
                rset12.close();
2825
                stmt12.close();
2826
 
2827
                // get released advisory ripple info
2828
                mLogger.debug("queryPackageVersions: stmt14");
2829
                phase.setPhase("getAllPkgs6");
2830
                PreparedStatement stmt14 = mConnection.prepareStatement(
2831
                        "select rc.pv_id " +
2832
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.advisory_ripple ar " +
7176 dpurdie 2833
                                "where rc.rtag_id=?" +
6914 dpurdie 2834
                                " and pv.pv_id = rc.pv_id and ar.rtag_id=rc.rtag_id and ar.pv_id=rc.pv_id " +
2835
                                "order by rc.pv_id"
2836
                        );
2837
                stmt14.setFetchSize(1000);
7176 dpurdie 2838
                stmt14.setInt(1, baseline);
7023 dpurdie 2839
                RmResultSet rset14 = new RmResultSet(stmt14.executeQuery(), "queryPackageVersions rset14");
6914 dpurdie 2840
 
2841
                while( rset14.next() )
2842
                {
7023 dpurdie 2843
                    int pv_id = rset14.mustGetInt("pv_id");
7186 dpurdie 2844
                    Package p = packageCollection.contains(pv_id);
2845
                    if ( p != null )
6914 dpurdie 2846
                    {
2847
                        p.mAdvisoryRipple = true;
2848
                    }
2849
                }
2850
 
2851
                rset14.close();
2852
                stmt14.close();
7023 dpurdie 2853
 
6914 dpurdie 2854
            }
2855
            else
2856
            {
2857
                // Escrow Mode
2858
                // get released product info
2859
                mLogger.debug("queryPackageVersions: stmt18");
2860
                PreparedStatement stmt = mConnection.prepareStatement(
2861
                        "select oc.prod_id, p.pkg_name, pv.pkg_version, pv.v_ext," +
2862
                                "release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag" +
2863
                                " from deployment_manager.bom_contents bc," +
2864
                                "deployment_manager.operating_systems os," +
2865
                                "deployment_manager.os_contents oc," +
2866
                                "release_manager.package_versions pv," +
2867
                                "release_manager.packages p" +
7176 dpurdie 2868
                                " where bc.bom_id=?" +
6914 dpurdie 2869
                                " and os.node_id=bc.node_id" +
2870
                                " and oc.os_id=os.os_id" +
2871
                                " and pv.pv_id=oc.prod_id" +
2872
                                " and p.pkg_id=pv.pkg_id" +
2873
                                " order by oc.prod_id"
2874
                        );
2875
                stmt.setFetchSize(1000);
7176 dpurdie 2876
                stmt.setInt(1, baseline);
7023 dpurdie 2877
                RmResultSet rset = new RmResultSet(stmt.executeQuery(), "queryPackageVersions rset");
6914 dpurdie 2878
 
2879
                while( rset.next() )
2880
                {
7023 dpurdie 2881
                    int pv_id = rset.mustGetKeyInt("prod_id");
2882
                    String pkg_name = rset.mustGetString("pkg_name");
2883
                    String pkg_version = rset.mustGetString("pkg_version");
2884
                    String v_ext = rset.getString("v_ext", "");
2885
                    String vcs_tag = rset.getString("vcsTag","");
2886
 
7186 dpurdie 2887
                    Package p = packageCollection.contains(pv_id);
2888
                    if ( p == null )
6914 dpurdie 2889
                    {
2890
                        Package q = new Package(0, pv_id, pkg_name, pkg_version, v_ext, pkg_name + "." + pkg_version, vcs_tag, 'x');
2891
                        packageCollection.add(q);
2892
                    }
2893
                }
2894
 
2895
                rset.close();
2896
                stmt.close();
7044 dpurdie 2897
 
2898
                //  Now have all the package-versions used in the SBOM need to 
2899
                //      determine all the dependent packages 
2900
                //      determine the build info for all the packages
2901
 
2902
                //  Determine all dependent packages
2903
                //  Note: use a ListIterator as it allows traverseDependencies to modify the packageCollection
2904
                for (ListIterator<Package> it = packageCollection.listIterator(); it.hasNext(); )
2905
                {
2906
                    Package p = it.next();
2907
                    traverseDependencies(packageCollection, p, false, it);
2908
                }
2909
 
2910
                //  Add required build information
2911
                for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
2912
                {
2913
                    Package p = it.next();
2914
                    queryBuildInfo(rippleEngine, p);
2915
                }
6914 dpurdie 2916
            }
2917
        }
2918
        catch ( SQLException e )
2919
        {
2920
            handleSQLException(e, "");
2921
        }
7088 dpurdie 2922
        phase.setPhase("End");
2923
    }
2924
 
2925
    /**
2926
     * Extract all package-version information for Planned Packages (WIPS)
2927
     * Not used in ESCROW
2928
     * 
2929
     * @param   rippleEngine        - Instance to use
2930
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2931
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
2932
     *  
2933
     * Overridden in ReleaseManagerUtf
2934
     *  
2935
     */
7186 dpurdie 2936
    protected void queryWips(RippleEngine rippleEngine, PackageCollection packageCollection, int baseline) throws SQLException, Exception
7088 dpurdie 2937
    {
2938
        if (!mDaemon){
2939
            return;
2940
        }
2941
 
2942
        Phase phase = new Phase("rmData");
2943
        mLogger.debug("queryWips {}", mDaemon);
2944
 
2945
        try
2946
        {
2947
            // Get planned package info
2948
            // Support multiple WIPS on the same package and build in the order they were released
2949
            // These are packages that are marked as pending build
2950
            //
2951
            mLogger.debug("queryPackageVersions: stmt1");
2952
            phase.setPhase("getPlannedPkgs1");
2953
            PreparedStatement stmt1 = mConnection.prepareStatement(
2954
                    "select pl.pv_id, pv.modified_stamp" +
2955
                            " from release_manager.planned pl," +
2956
                            "      release_manager.package_versions pv," +
2957
                            "      release_manager.packages p" +
7176 dpurdie 2958
                            " where pl.rtag_id=?" +
7088 dpurdie 2959
                            "   and pv.build_type='A' and pv.dlocked='A'" +
2960
                            "   and pv.pv_id=pl.pv_id and p.pkg_id=pv.pkg_id" +
2961
                            " order by pv.modified_stamp"
2962
                    );
2963
            stmt1.setFetchSize(500);
7176 dpurdie 2964
            stmt1.setInt(1, baseline);
7088 dpurdie 2965
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "queryPackageVersions rset1");
2966
 
2967
            while( rset1.next() )
2968
            {
2969
                int pvId = rset1.mustGetKeyInt("pv_id");
2970
 
7099 dpurdie 2971
                Package p = getPackageInfo(pvId, rippleEngine, true);
7088 dpurdie 2972
                if ( p != NULL_PACKAGE)
2973
                {
2974
                    p.mIsNotReleased = true;
2975
                    p.mDirectlyPlanned = true;
2976
                    p.mBuildReason = BuildReason.NewVersion;
2977
 
2978
                    // If there are multiple packages with the same Alias, then only the first one
2979
                    // will be placed in the build set. The will be the oldest, the first one released
2980
                    // to be built
2981
 
7186 dpurdie 2982
                    Package prevPlannedPackage = packageCollection.contains(p.mAlias);
2983
                    if ( prevPlannedPackage == null )
7088 dpurdie 2984
                    {
7176 dpurdie 2985
                        mLogger.debug("queryWips rset1 no previous WIP package {}", pvId);
7088 dpurdie 2986
                        packageCollection.add(p);
2987
                    }
2988
                }
2989
            }
2990
 
2991
            rset1.close();
2992
            stmt1.close();
2993
 
2994
            //  Process Scheduled Build Approvals. OpCode is 2
2995
            //      These are treated as requests to not-include a 'Pending' package-version in the current build set
2996
            //      If there is an un-expired instruction, then remove the pending package-version from the build set
2997
            //
2998
            //  Process all expired requests
2999
            //      These are scheduled builds were the scheduled time has been exceeded
3000
            //      Simply discard the instruction and let the Approved build proceed
3001
            //
3002
            DaemonInstruction di = new DaemonInstruction(baseline, 2, true);
3003
 
3004
            phase.setPhase("removeOldSchedBuilds");
3005
            while ( getDaemonInst( di ) )
3006
            {
3007
                markDaemonInstCompleted(di.instruction);
3008
                mLogger.info("queryPackageVersions remove Scheduled Build Approvals {}", di.pvId);
3009
            }
3010
 
3011
            phase.setPhase("getSchedBuilds");
3012
            di = new DaemonInstruction(baseline, 2, false);
3013
            while ( getDaemonInst( di ) )
3014
            {
7186 dpurdie 3015
                Package p = packageCollection.contains(di.pvId); 
3016
                if ( p != null )
7088 dpurdie 3017
                {
3018
                    mLogger.info("queryPackageVersions Scheduled Build Approvals {}", di.pvId);
3019
                    packageCollection.remove(p);
3020
                }
3021
                else
3022
                {
3023
                    // discard - the package no longer exists
3024
                    markDaemonInstCompleted( di.instruction );
3025
                    mLogger.info("queryPackageVersions remove Scheduled Build Approvals for nonexistent package {}", di.pvId);
3026
                }
3027
            }                
3028
 
3029
        }
7082 dpurdie 3030
        catch ( SQLException e )
3031
        {
3032
            handleSQLException(e, "");
3033
        }
6914 dpurdie 3034
        phase.setPhase("End");
3035
    }
3036
 
7082 dpurdie 3037
    /**
3038
     * Extract all TEST package-version information
3039
     * Only active in Daemon Mode
3040
     * 
3041
     * @param   rippleEngine        - Instance to use
3042
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
3043
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
3044
     *  
3045
     * Overridden in ReleaseManagerUtf
3046
     *  
3047
     */
7186 dpurdie 3048
    protected void queryTest(RippleEngine rippleEngine, PackageCollection packageCollection, int baseline) throws SQLException, Exception
7082 dpurdie 3049
    {
3050
        if (!mDaemon){
3051
            return;
3052
        }
3053
 
3054
        Phase phase = new Phase("rmData");
3055
        mLogger.debug("queryTest {}", mDaemon);
3056
 
3057
        try
3058
        {
3059
 
3060
            // Daemon Instruction: Test Build Package
3061
            //  An op code of 1 means test build
3062
            //
3063
            // Trust nothing - these are mostly wips that at any time may have:
3064
            // - no build location
3065
            // - no build label
3066
            // - an empty build standard collection
3067
            // proceed with defaults above if necessary (the build will subsequently fail)
3068
            // in all cases, build a meaningful email body to inform the user
3069
            // of the snapshot of build information that applied to the build and store in:
3070
            // - mTestBuildEmailBody
3071
 
3072
            mLogger.debug("queryTest: stmt141");
3073
            phase.setPhase("getTestBuild1");
3074
            DaemonInstruction di = new DaemonInstruction( baseline, 1, true);
3075
            while ( getDaemonInst( di ) )
3076
            {
7176 dpurdie 3077
                mLogger.debug("queryPackageVersions test build data {}", di.pvId);
7082 dpurdie 3078
 
7099 dpurdie 3079
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7082 dpurdie 3080
                if ( p == NULL_PACKAGE )
3081
                {
3082
                    mLogger.error("queryTest rset15 no data found {}", di.instruction);
3083
                    markDaemonInstCompleted( di.instruction );
3084
 
3085
                }
3086
                else
3087
                {
3088
                    packageCollection.add(p);
3089
 
3090
                    //  Set some Test information
3091
                    //  Avoid interaction with real versions
7186 dpurdie 3092
                    //  Flag as not peg ed - so that we test build
3093
 
7082 dpurdie 3094
                    p.mTestBuildInstruction = di.instruction;
3095
                    p.addEmail(di.userEmail);
3096
                    p.mBuildReason = BuildReason.Test;
3097
                    p.mIsPegged = false;
3098
                    p.mIsNotReleased = true;
3099
                }
3100
            }
3101
        }
3102
        catch ( SQLException e )
3103
        {
3104
            handleSQLException(e, "");
3105
        }
3106
        phase.setPhase("End");
3107
    }
6914 dpurdie 3108
 
7082 dpurdie 3109
    /**
3110
     * Extract all Ripple Request package-version information
3111
     * The returned list is in daemon instruction id order - ie the first request will be first
3112
     * Only active in Daemon Mode
3113
     * 
3114
     * @param   rippleEngine        - Instance to use
3115
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
3116
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
3117
     *  
3118
     * Overridden in ReleaseManagerUtf
3119
     *  
3120
     */
7186 dpurdie 3121
    protected void queryRipples(RippleEngine rippleEngine, PackageCollection packageCollection, int baseline) throws SQLException, Exception
7082 dpurdie 3122
    {
3123
        if (!mDaemon){
3124
            return;
3125
        }
3126
 
3127
        Phase phase = new Phase("rmData");
3128
        mLogger.debug("queryPackageVersions {}", mDaemon);
3129
 
3130
        try
3131
        {
3132
            // Daemon Instruction: Force Package Ripple
3133
            //  An op code of 0 means force ripple
3134
 
3135
            phase.setPhase("getDaemonInstructions1");
3136
            DaemonInstruction di = new DaemonInstruction( baseline, 0, true);
3137
            while ( getDaemonInst( di ) )
3138
            {
7099 dpurdie 3139
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7082 dpurdie 3140
                if ( p != NULL_PACKAGE )
3141
                {
7176 dpurdie 3142
                    mLogger.debug("queryPackageVersions forced ripple data {}", di.pvId);
7082 dpurdie 3143
                    packageCollection.add(p);
3144
                    p.mForcedRippleInstruction = di.instruction;
3145
                    p.addEmail(di.userEmail);
7099 dpurdie 3146
                    p.mBuildReason = BuildReason.Forced;
7082 dpurdie 3147
                    p.mIsNotReleased = true;
3148
                }
3149
                else
3150
                {
3151
                    // discard
3152
                    markDaemonInstCompleted( di.instruction );
3153
                }
3154
            }
3155
 
3156
        }
3157
        catch ( SQLException e )
3158
        {
3159
            handleSQLException(e, "");
3160
        }
3161
        phase.setPhase("End");
3162
    }
3163
 
3164
    /** Get all build information for a single package
3165
     *  Don't use this where lots of packages are expected, but should be OK to get data for TEST, WIP and Ripples
3166
     *  
3167
     *  Does not get:
3168
     *      mBuildReason
3169
     *      mDirectlyPlanned
3170
     *  
3171
     *  @param  pvId    - Package to process
3172
     * @param rippleEngine - Ripple engine associated wit the Release
7099 dpurdie 3173
     * @param useChangeType - true: For a WIP, the change type is significant
7082 dpurdie 3174
     * @throws Exception 
3175
     *  
3176
     *  @returns a package - May be null, but this is not good
3177
     */
7099 dpurdie 3178
    Package getPackageInfo(int pvId, RippleEngine rippleEngine, boolean useChangeType) throws Exception
7082 dpurdie 3179
    {
3180
        Package p = NULL_PACKAGE;
3181
 
3182
        try
3183
        {
3184
            // Get Package info
3185
            //
3186
            mLogger.debug("getPackageInfo: stmt1");
3187
            PreparedStatement stmt1 = mConnection.prepareStatement(
3188
                    "select pv.pv_id, p.pkg_id, p.pkg_name, pv.pkg_version, " +
3189
                            " pv.v_ext, pv.change_type, pv.ripple_field," +
3190
                            " pv.major_limit, pv.minor_limit, pv.patch_limit, pv.build_number_limit," +
3191
                            " pv.modified_stamp," +
3192
                            " release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag," +
3193
                            " pv.build_time" +
3194
                            " from " +
3195
                            "      release_manager.package_versions pv," +
3196
                            "      release_manager.packages p" +
7176 dpurdie 3197
                            " where pv.pv_id=?" +
7082 dpurdie 3198
                            "   and p.pkg_id=pv.pkg_id"
3199
 
3200
                    );
7176 dpurdie 3201
            stmt1.setInt(1, pvId);
7082 dpurdie 3202
            stmt1.setFetchSize(500);
3203
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "getPackageInfo rset1");
3204
 
3205
            //  Package must exist
3206
            if ( ! rset1.next() )
3207
            {
3208
                return NULL_PACKAGE;
3209
            }
3210
 
3211
 
3212
            int pv_id = rset1.mustGetKeyInt("pv_id");
3213
            int pkg_id = rset1.mustGetInt("pkg_id");
3214
            String pkg_name = rset1.mustGetString("pkg_name");
3215
            String pkg_version = rset1.mustGetString("pkg_version");
3216
            int buildTime = rset1.getInt("build_time", 60);
3217
 
3218
            // Previous Version of this package, without the project suffix
3219
            String pkg_prevVersion = getBaseVersionNumber(pv_id);
3220
            if ( pkg_prevVersion == null)
3221
            {
3222
                // show stopper
3223
                mLogger.error("getPackageInfo. No Previous version {}", pv_id);
3224
                throw new Exception("getPackageInfo. No Previous version" + pv_id);
3225
            }
3226
 
3227
            String v_ext = rset1.getString("v_ext","");
3228
            String change_type = rset1.getString("change_type", "P");
3229
 
3230
            char ct = 'P';
3231
 
3232
            if ( change_type.compareTo("M") == 0 )
3233
            {
3234
                ct = 'M';
3235
            }
3236
            else if ( change_type.compareTo("N") == 0 )
3237
            {
3238
                ct = 'N';
3239
            }
3240
            else if ( change_type.compareTo("P") == 0 )
3241
            {
3242
                ct = 'P';
3243
            }
3244
            else if ( change_type.compareTo("F") == 0 )
3245
            {
3246
                ct = 'F';
3247
            }
3248
 
3249
            String ripple_field = rset1.getString("ripple_field", "b");
3250
            int major_limit = rset1.getInt("major_limit", 0);
3251
            int minor_limit = rset1.getInt("minor_limit",0);
3252
            int patch_limit = rset1.getInt("patch_limit",0);
3253
            int build_number_limit = rset1.getInt("build_number_limit",0);
3254
            String vcs_tag = rset1.getString("vcsTag", "");
7099 dpurdie 3255
 
3256
            if ( useChangeType ) {
7169 dpurdie 3257
                //  WIP - Change type is significant
3258
                //        The next version number will be based on the previous version number of the package
3259
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0), ct);
3260
                p.mPrevVersion = pkg_prevVersion;
3261
 
7099 dpurdie 3262
            } else {
7169 dpurdie 3263
                //  RIPPLE/TEST - Change type is not significant
3264
                //                Next version number will will be based on the current version number
7099 dpurdie 3265
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
3266
            }
7082 dpurdie 3267
            p.mMajorLimit = major_limit;
3268
            p.mMinorLimit = minor_limit;
3269
            p.mPatchLimit = patch_limit;
3270
            p.mBuildLimit = build_number_limit;
3271
            p.mBuildTime = buildTime;
3272
 
3273
            rset1.close();
3274
            stmt1.close();
3275
 
3276
            // get Package dependency info
3277
            mLogger.debug("getPackageInfo: stmt2");
3278
            PreparedStatement stmt2 = mConnection.prepareStatement(
7099 dpurdie 3279
                    "select p.pkg_name, dpv.v_ext, dpv.pv_id" +
7082 dpurdie 3280
                            " from " +
3281
                            "     release_manager.package_versions pv,"+
3282
                            "     release_manager.package_dependencies pd," +
7099 dpurdie 3283
                            "     release_manager.package_versions dpv,"+
3284
                            "     release_manager.packages p" +
7176 dpurdie 3285
                            " where pv.pv_id=?" + 
7082 dpurdie 3286
                            "  and pd.pv_id=pv.pv_id"+
7099 dpurdie 3287
                            "  and dpv.pv_id=pd.dpv_id" +
3288
                            "  and pd.dpkg_id = p.pkg_id"
7082 dpurdie 3289
                    );
3290
            stmt2.setFetchSize(500);
7176 dpurdie 3291
            stmt2.setInt(1, pvId);
7082 dpurdie 3292
            RmResultSet rset2 = new RmResultSet(stmt2.executeQuery(), "getPackageInfo rset2");
3293
 
3294
            while ( rset2.next() )
3295
            {
7099 dpurdie 3296
                String dpv_name = rset2.mustGetKeyString("pkg_name");
7114 dpurdie 3297
                String dpv_ext = rset2.getString("v_ext","");
7082 dpurdie 3298
                int    dpvId = rset2.mustGetInt("pv_id");
3299
 
7163 dpurdie 3300
                p.addDependency(dpv_name + dpv_ext, dpvId);
7082 dpurdie 3301
            }
3302
 
3303
            rset2.close();
3304
            stmt2.close();
3305
 
3306
            // get Package build info
3307
            mLogger.debug("getPackageInfo: stmt3");
3308
            PreparedStatement stmt3 = mConnection.prepareStatement(
3309
                    "select bm.bm_name, bsa.bsa_name" +
3310
                            " from " +
3311
                            "   release_manager.package_versions pv," +
3312
                            "   release_manager.package_build_info pbi," +
3313
                            "   release_manager.build_machines bm," +
3314
                            "   release_manager.build_standards_addendum bsa " +
7176 dpurdie 3315
                            " where pv.pv_id=?" + 
7082 dpurdie 3316
                            "   and pbi.pv_id=pv.pv_id" +
3317
                            "   and bm.bm_id=pbi.bm_id" +
3318
                            "   and bsa.bsa_id=pbi.bsa_id "
3319
                    );
3320
            stmt3.setFetchSize(500);
7176 dpurdie 3321
            stmt3.setInt(1, pvId);
7082 dpurdie 3322
            RmResultSet rset3 = new RmResultSet(stmt3.executeQuery(), "getPackageInfo rset3");
3323
 
3324
            while ( rset3.next() )
3325
            {
3326
                String bm_name = rset3.mustGetString("bm_name");
3327
                String bsa_name = rset3.mustGetString("bsa_name");
3328
 
3329
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3330
                if ( bs.supportedBuildStandard() )
3331
                {
3332
                    p.mBuildStandardCollection.add(bs);
3333
                }
3334
            }
3335
 
3336
            rset3.close();
3337
            stmt3.close();
3338
 
3339
            // get Package unit test info
3340
            mLogger.debug("getPackageInfo: stmt4");
3341
            PreparedStatement stmt4 = mConnection.prepareStatement(
3342
                    "select pv.pv_id, tt.test_type_name" +
3343
                    "  from "+
3344
                    "       release_manager.package_versions pv,"+
3345
                    "       release_manager.unit_tests ut," +
3346
                    "       release_manager.test_types tt" +
7176 dpurdie 3347
                    " where pv.pv_id=?" + 
7082 dpurdie 3348
                    "  and ut.pv_id=pv.pv_id" +
3349
                    "  and tt.test_type_id=ut.test_types_fk"
3350
                    );
3351
            stmt4.setFetchSize(500);
7176 dpurdie 3352
            stmt4.setInt(1, pvId);
7082 dpurdie 3353
            RmResultSet rset4 = new RmResultSet(stmt4.executeQuery(), "getPackageInfo rset4");
3354
 
3355
            while ( rset4.next() )
3356
            {
3357
                String test_type_name = rset4.mustGetString("test_type_name");
3358
                if ( test_type_name.compareTo("Autobuild UTF") == 0 )
3359
                {
3360
                    p.mHasAutomatedUnitTests = true;
3361
                }
3362
            }
3363
 
3364
            rset4.close();
3365
            stmt4.close();
3366
 
3367
            // get Package build failure info...
3368
            //      view based
3369
            mLogger.debug("getPackageInfo: stmt5");
3370
            PreparedStatement stmt5 = mConnection.prepareStatement(
3371
                    "SELECT rc.pv_id," +
3372
                            "  u.user_email" +
3373
                            " FROM release_manager.release_content rc," +
3374
                            "  release_manager.release_tags rt," +
3375
                            "  release_manager.package_versions pv," +
3376
                            "  release_manager.autobuild_failure af," +
3377
                            "  release_manager.members_group mg," +
3378
                            "  release_manager.users u" +
7176 dpurdie 3379
                            " WHERE rc.rtag_id     = ?" +
7082 dpurdie 3380
                            " AND rt.rtag_id       = rc.rtag_id" +
7176 dpurdie 3381
                            " AND pv.pv_id         =?" +
7082 dpurdie 3382
                            " AND pv.pv_id         = rc.pv_id" +
3383
                            " AND af.view_id       = rc.base_view_id" +
3384
                            " AND mg.group_email_id= af.group_email_id" +
3385
                            " AND u.user_id        = mg.user_id" +
3386
                            " AND af.proj_id       = rt.proj_id"
3387
                    );
3388
            stmt5.setFetchSize(500);
7176 dpurdie 3389
            stmt5.setInt(1, rippleEngine.getRtagId());
3390
            stmt5.setInt(2, pvId);
3391
 
3392
 
7082 dpurdie 3393
            RmResultSet rset5 = new RmResultSet(stmt5.executeQuery(), "getPackageInfo rset5");
3394
 
3395
            while ( rset5.next() )
3396
            {
3397
                p.addEmail(rset5.getString("user_email", null));
3398
            }
3399
 
3400
            rset5.close();
3401
            stmt5.close();
3402
 
3403
            // get Package build failure info...
3404
            // package version
3405
            mLogger.debug("getPackageInfo: stmt6");
3406
            PreparedStatement stmt6 = mConnection.prepareStatement(
3407
                    "select pv.pv_id, u1.user_email as creator, u2.user_email as owner, u3.user_email as modifier" +
3408
                    " from " +
3409
                    "      release_manager.release_tags rt," +
3410
                    "      release_manager.package_versions pv," +
3411
                    "      release_manager.users u1," +
3412
                    "      release_manager.users u2," +
3413
                    "      release_manager.users u3 " +
7176 dpurdie 3414
                    " where pv.pv_id=?" +  
3415
                    "   and rt.rtag_id=?" + 
7082 dpurdie 3416
                    "   and pv.build_type='A'" +
3417
                    "   and pv.dlocked='A' " +
3418
                    "   and u1.user_id=pv.creator_id" +
3419
                    "   and u2.user_id=pv.owner_id" +
3420
                    "   and u3.user_id=pv.modifier_id"
3421
                    );
3422
            stmt6.setFetchSize(500);
7176 dpurdie 3423
            stmt6.setInt(1, pvId);
3424
            stmt6.setInt(2, rippleEngine.getRtagId());
3425
 
7082 dpurdie 3426
            RmResultSet rset6 = new RmResultSet(stmt6.executeQuery(), "getPackageInfo rset6");
3427
 
3428
            while ( rset6.next() )
3429
            {
3430
                p.addEmail( rset6.getString("creator",null));
3431
                p.addEmail( rset6.getString("owner",null));
3432
                p.addEmail( rset6.getString("modifier",null));
3433
            }
3434
 
3435
            rset6.close();
3436
            stmt6.close();
3437
 
3438
            // get Package advisory ripple info
3439
            mLogger.debug("getPackageInfo: stmt7");
3440
            PreparedStatement stmt7 = mConnection.prepareStatement(
3441
                    "select pv.pv_id, pv.modified_stamp " +
3442
                    " from " +
3443
                    "      release_manager.package_versions pv," +
3444
                    "      release_manager.advisory_ripple ar " +
7176 dpurdie 3445
                    " where pv.pv_id = ?" +
3446
                    "    and ar.rtag_id= ?" +
7082 dpurdie 3447
                    "    and ar.pv_id=pv.pv_id "
3448
                    );
3449
            stmt7.setFetchSize(500);
7176 dpurdie 3450
            stmt7.setInt(1, pvId);
3451
            stmt7.setInt(2, rippleEngine.getRtagId());
3452
 
7082 dpurdie 3453
            RmResultSet rset7 = new RmResultSet(stmt7.executeQuery(), "getPackageInfo rset7");
3454
 
3455
            if( rset7.next() )
3456
            {
3457
                p.mAdvisoryRipple = true;
3458
            }
3459
 
3460
            rset7.close();
3461
            stmt7.close();            
3462
 
3463
        }
3464
        catch ( SQLException e )
3465
        {
3466
            handleSQLException(e, "");
3467
        }
3468
 
3469
        return p;
3470
    }
3471
 
7169 dpurdie 3472
    /** Extract PlanControl data for a specific release
3473
     * 
3474
     *  Overridden in ReleaseManagerUtf
3475
     * 
3476
     * @param mRtagId - Release to process
3477
     * @param mPlanControl  - Data is inserted into this object
3478
     * @throws Exception 
3479
     */
3480
    public void queryPlanControl(int mRtagId, PlanControl mPlanControl) throws Exception {
3481
        mLogger.debug("queryPlanControl {}", mRtagId);
3482
 
3483
        if ( mUseDatabase )
3484
        {
3485
            try
3486
            {
3487
                CallableStatement stmt = mConnection.prepareCall(
3488
                        "SELECT PLAN_THRESHOLD, PLAN_DROP" + 
3489
                        " FROM release_manager.release_tags rt" + 
3490
                        " WHERE rt.rtag_id  = ?"
3491
                        );
3492
                stmt.setInt(1, mRtagId);
3493
                RmResultSet rset = new RmResultSet(stmt.executeQuery(), "queryPlanControl");
3494
 
3495
                if( rset.next() )
3496
                {
3497
                    mPlanControl.setThreshold(rset.mustGetInt("PLAN_THRESHOLD"));
3498
                    mPlanControl.setDumpPlan(rset.mustGetString("PLAN_DROP"));
3499
                } else
3500
                {
3501
                    mLogger.error("queryPlanControl did not return data");
3502
                    // show stopper
3503
                    throw new Exception("queryPlanControl did not return data");
3504
                }
3505
                rset.close();
3506
                stmt.close();            
3507
            }
3508
            catch ( SQLException e )
3509
            {
3510
                handleSQLException(e, "");
3511
            }
3512
        }
3513
 
7176 dpurdie 3514
        mLogger.debug("queryPlanControl {}", mPlanControl);
7169 dpurdie 3515
    }
3516
 
7082 dpurdie 3517
    /**	Determine the version number of the base package
6914 dpurdie 3518
    *   Used in a ripple build to determine the base for calculating the next version number
3519
    *   Assumes that a database connection has been established
3520
    *   Used in Daemon Mode Only
3521
    *   
3522
    *   History: Used to determine the last non-rippled package, but this had issues [JATS-402]
3523
    *   This version will located the last release version with a check that it is not a WIP ( ie start with a '(' )
3524
    *   
3525
    *   @param pv_id	- The PVID of the package to process
3526
    *   @return         - The version number without a project suffix. Null on error. 0.0.0000 if no previous
3527
    *   @throws SQLException 
3528
    */
3529
    public String getBaseVersionNumber(int pv_id)
3530
    {
3531
    	String baseVersion = "0.0.0000";
3532
 
3533
    	try {
3534
    		CallableStatement stmt;
3535
			stmt = mConnection.prepareCall(
3536
					"SELECT pv_id,last_pv_id,pkg_version,v_ext,build_type, DLOCKED " +
3537
					" FROM " +
3538
					"  (SELECT build_type,last_pv_id,pv_id,pkg_version,v_ext, DLOCKED " +
3539
					"  FROM " +
3540
					"    (SELECT pv.build_type,pv.last_pv_id AS raw_last_pvid ,pv_id,pv.pkg_version,pv.v_ext,DECODE(pv.pv_id, pv.last_pv_id, NULL, pv.last_pv_id) AS last_pv_id, DLOCKED " +
3541
					"    FROM release_manager.package_versions pv " +
3542
					"    WHERE pv.PKG_ID IN " +
3543
					"      (SELECT pkg_id " +
3544
					"      FROM release_manager.package_versions pv " +
7169 dpurdie 3545
					"      WHERE pv.pv_id = ?" +
6914 dpurdie 3546
					"      ) " +
3547
					"    ) " +
7169 dpurdie 3548
					"    START WITH pv_id = ?" +
6914 dpurdie 3549
					"    CONNECT BY nocycle prior last_pv_id = pv_id " +
3550
					"  ) " +
7169 dpurdie 3551
					" WHERE DLOCKED = 'Y' and pkg_version not like '(%' AND pv_id != ?"
6914 dpurdie 3552
	                   //" WHERE build_type != 'Y' and pv_id != " + pv_id
3553
			        );
7169 dpurdie 3554
			stmt.setInt(1, pv_id);
3555
			stmt.setInt(2, pv_id);
3556
			stmt.setInt(3, pv_id);
3557
 
6914 dpurdie 3558
			ResultSet rset = stmt.executeQuery();
3559
 
3560
			while( rset.next() )
3561
			{
3562
				// Previous Version of this package, without the project suffix
7201 dpurdie 3563
				String pkgPrevVersion = rset.getString("pkg_version");
3564
				if (pkgPrevVersion != null) 
6914 dpurdie 3565
				{
7201 dpurdie 3566
					String pkgPrevVext = rset.getString("v_ext");
3567
					if (pkgPrevVext != null) 
6914 dpurdie 3568
					{
7201 dpurdie 3569
						int endindex = pkgPrevVersion.length() - pkgPrevVext.length();
6914 dpurdie 3570
						if ( endindex > 0 )
3571
						{
7201 dpurdie 3572
							baseVersion = pkgPrevVersion.substring(0, endindex);
6914 dpurdie 3573
						}
3574
					}
3575
				}
3576
 
3577
				// Only want the first entry
3578
				break;
3579
			}
3580
 
3581
			rset.close();
3582
			stmt.close();
3583
 
3584
    	} catch (SQLException e) {
3585
    		baseVersion = null;
7044 dpurdie 3586
    		mLogger.error("Exception for getBaseVersionNumber {}", pv_id);
6914 dpurdie 3587
		}
3588
        return baseVersion;
3589
    }
3590
 
7044 dpurdie 3591
    /** Called only in escrow mode
3592
     * 
3593
     * Used to process each package in the escrow list and to locate all dependent packages - recursively.
3594
     * 
6914 dpurdie 3595
     * if checkCollection is true, checks the pv_id is in the packageCollection
3596
     * if checkCollection is false, or the pv_id is not in the collection
7044 dpurdie 3597
     *    Traverses the pv_id package dependencies
3598
     *    for each dpv.pv_id in the resultset
6914 dpurdie 3599
     *     call traverseDependencies( packageCollection, dpv.pv_id, true )
3600
     *     if the pv_id is not in the collection, add it
7044 dpurdie 3601
     * 
3602
     *   @param packageCollection   - Collection of packages being processed
3603
     *   @param pkg                 - Current package in the collection
3604
     *   @param checkCollection     - How to handle pkg not in the collection. False: Process all package dependencies. True: Skip if package is in collection
3605
     *   @param listIterator        - List iterator being used to iterate over packageCollection. Used to insert new packages
6914 dpurdie 3606
     *   
7044 dpurdie 3607
     *   This function is called recursively
6914 dpurdie 3608
     */
7186 dpurdie 3609
    private void traverseDependencies(PackageCollection packageCollection, Package pkg, boolean checkCollection, ListIterator<Package> listIterator) throws SQLException, Exception
7044 dpurdie 3610
    {
3611
        mLogger.debug("traverseDependencies {}", checkCollection);
6914 dpurdie 3612
        boolean pvIdInCollection = false;
3613
 
3614
        if ( checkCollection )
3615
        {
7186 dpurdie 3616
        	Package p = packageCollection.contains(pkg.mId);
3617
        	if (p != null)
3618
        		pvIdInCollection = true;
6914 dpurdie 3619
        }
3620
 
3621
        if ( !pvIdInCollection )
3622
        {
3623
            ArrayList<Package> resultset = new ArrayList<Package>();
3624
 
3625
            try
3626
            {
3627
                PreparedStatement stmt = mConnection.prepareStatement(
3628
                        "select dpv.pv_id," +
3629
                                "p.pkg_name," + 
3630
                                "dpv.pkg_version," +
3631
                                "dpv.v_ext," + 
3632
                                "release_manager.PK_RMAPI.return_vcs_tag(dpv.pv_id) AS vcsTag" + 
3633
                                " from release_manager.package_versions pv," + 
3634
                                "release_manager.package_dependencies pd," + 
3635
                                "release_manager.package_versions dpv," + 
3636
                                "release_manager.packages p" + 
7176 dpurdie 3637
                                " where pv.pv_id=?" + 
6914 dpurdie 3638
                                "   and pd.pv_id=pv.pv_id" +
3639
                                "   and dpv.pv_id=pd.dpv_id" + 
3640
                                "   and p.pkg_id=dpv.pkg_id" + 
3641
                        " order by pv.pv_id");
7176 dpurdie 3642
                stmt.setInt(1, pkg.mId);
6914 dpurdie 3643
                stmt.setFetchSize(1000);
7023 dpurdie 3644
                RmResultSet rset = new RmResultSet(stmt.executeQuery(),"traverseDependencies");
6914 dpurdie 3645
 
3646
                while (rset.next())
3647
                {
7201 dpurdie 3648
                    int pvId = rset.mustGetKeyInt("pv_id");
3649
                    String pkgName = rset.mustGetString("pkg_name");
3650
                    String pkgVersion = rset.mustGetString("pkg_version");
3651
                    String vExt = rset.getString("v_ext","");
3652
                    String vcsTag = rset.getString("vcsTag","");
6914 dpurdie 3653
 
7201 dpurdie 3654
                    Package p = new Package(0, pvId, pkgName, pkgVersion, vExt, pkgName + "." + pkgVersion, vcsTag, 'x');
6914 dpurdie 3655
                    resultset.add(p);
7163 dpurdie 3656
                    pkg.addDependency(p.mAlias, -1);
6914 dpurdie 3657
                }
3658
 
3659
                rset.close();
3660
                stmt.close();
3661
            }
3662
            catch ( SQLException e )
3663
            {
3664
                handleSQLException(e, "");
3665
            }
3666
 
7044 dpurdie 3667
            //  Process each dependent package
6914 dpurdie 3668
            for (Iterator<Package> it = resultset.iterator(); it.hasNext();)
3669
            {
3670
                Package r = it.next();
3671
                traverseDependencies(packageCollection, r, true, listIterator);
3672
 
3673
                pvIdInCollection = false;
7186 dpurdie 3674
                Package p = packageCollection.contains(r.mId);
3675
            	if (p != null)
3676
            		pvIdInCollection = true;
3677
 
6914 dpurdie 3678
                if (!pvIdInCollection)
3679
                {
3680
                    // insert the Package immediately before the next Package returned by next
3681
                    // this does not change the next Package (if any) to be returned by next
3682
                    listIterator.add(r);
3683
                }
3684
 
3685
            }
3686
        }
7044 dpurdie 3687
    }
6914 dpurdie 3688
 
7044 dpurdie 3689
    /** Called only in escrow mode
3690
     * 
3691
     *  <p>Add build information to a Package
3692
     *  <br>Adds: bm_name and bsa_name, but only if they are supported
3693
     * 
3694
     * @param   rippleEngine    - Ripple Engine being used
3695
     * @param   p               - Package to process
3696
     * 
6914 dpurdie 3697
     */
3698
    private void queryBuildInfo(RippleEngine rippleEngine, Package p) throws SQLException, Exception
3699
    {
3700
        mLogger.debug("queryBuildInfo");
3701
 
3702
        try
3703
        {
3704
            CallableStatement stmt = mConnection.prepareCall("select bm.bm_name, bsa.bsa_name "
3705
                    + "from release_manager.package_versions pv," 
3706
                    + "     release_manager.package_build_info pbi,"
3707
                    + "     release_manager.build_machines bm," 
3708
                    + "     release_manager.build_standards_addendum bsa "
7169 dpurdie 3709
                    + "where pv.pv_id=?" 
6914 dpurdie 3710
                    + "   and pbi.pv_id=pv.pv_id" 
3711
                    + "   and bm.bm_id=pbi.bm_id"
3712
                    + "   and bsa.bsa_id=pbi.bsa_id " 
3713
                    + "order by pv.pv_id");
7169 dpurdie 3714
            stmt.setInt(1, p.mId);
3715
 
7023 dpurdie 3716
            RmResultSet rset = new RmResultSet (stmt.executeQuery(),"queryBuildInfo");
6914 dpurdie 3717
 
3718
            while (rset.next())
3719
            {
7023 dpurdie 3720
                String bm_name = rset.mustGetKeyString("bm_name");
3721
                String bsa_name = rset.mustGetString("bsa_name");
6914 dpurdie 3722
 
3723
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3724
 
3725
                if (bs.supportedBuildStandard())
3726
                {
3727
                    p.mBuildStandardCollection.add(bs);
3728
                }
3729
            }
3730
 
3731
            rset.close();
3732
            stmt.close();
3733
        }
3734
        catch ( SQLException e )
3735
        {
3736
            handleSQLException(e, "");
3737
        }
3738
 
3739
    }
3740
 
3741
    /**only used in daemon mode to determine version existence in the database
3742
     *  1 select pkg_id from release_manager.package_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3743
     *  2 select pkg_id from release_manager.planned_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3744
     * returns true if either resultset contains one record to indicate it already exists
3745
     */
3746
    boolean queryPackageVersions(int pkg_id, String pkg_version) throws SQLException, Exception
3747
    {
3748
        mLogger.debug("queryPackageVersions");
3749
        boolean retVal = false;
3750
 
3751
        if ( mUseDatabase )
3752
        {
3753
            try
3754
            {
3755
                mLogger.info("queryPackageVersions release_manager.package_versions");
3756
                CallableStatement stmt1 = mConnection.prepareCall(
3757
                    "select pkg_id" +
3758
                    " from release_manager.package_versions" +
7169 dpurdie 3759
                    " where pkg_id=?" + 
3760
                    " and pkg_version=?");
3761
                stmt1.setInt(1, pkg_id);
3762
                stmt1.setString(2, pkg_version);
3763
 
6914 dpurdie 3764
                ResultSet rset1 = stmt1.executeQuery();
3765
                int rsetSize = 0;
3766
 
3767
                while( rset1.next() )
3768
                {
3769
                    rsetSize++;
3770
                }
3771
 
3772
                rset1.close();
3773
                stmt1.close();
3774
 
3775
                if ( rsetSize > 1 )
3776
                {
7044 dpurdie 3777
                    String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3778
                    mLogger.error(msg);
6914 dpurdie 3779
                    // show stopper
7044 dpurdie 3780
                    throw new Exception(msg);
6914 dpurdie 3781
                }
3782
 
3783
                if ( rsetSize == 1 )
3784
                {
3785
                    retVal = true;
3786
                }
3787
                else
3788
                {
3789
                    mLogger.info("queryPackageVersions release_manager.planned_versions");
3790
                    CallableStatement stmt2 = mConnection.prepareCall(
3791
                        "select pkg_id" +
3792
                        " from release_manager.planned_versions" +
7169 dpurdie 3793
                        " where pkg_id=?" + 
3794
                        " and pkg_version=?");
3795
                    stmt2.setInt(1, pkg_id);
3796
                    stmt2.setString(2, pkg_version);
3797
 
6914 dpurdie 3798
                    ResultSet rset2 = stmt2.executeQuery();
3799
                    rsetSize = 0;
3800
 
3801
                    while( rset2.next() )
3802
                    {
3803
                        rsetSize++;
3804
                    }
3805
 
3806
                    rset2.close();
3807
                    stmt2.close();
3808
 
3809
                    if ( rsetSize > 1 )
3810
                    {
7044 dpurdie 3811
                        String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3812
                        mLogger.error(msg);
6914 dpurdie 3813
                        // show stopper
7044 dpurdie 3814
                        throw new Exception(msg);
6914 dpurdie 3815
                    }
3816
 
3817
                    if ( rsetSize == 1 )
3818
                    {
3819
                        retVal = true;
3820
                    }
3821
                }
3822
            }
3823
            catch ( SQLException e )
3824
            {
3825
                handleSQLException(e, "");
3826
            }
3827
        }
3828
 
7176 dpurdie 3829
        mLogger.debug("queryPackageVersions returned {}", retVal);
6914 dpurdie 3830
        return retVal;
3831
    }
3832
 
3833
    /**
3834
     * Determine the set of packages that have been excluded from the build 
3835
     * These are packages that have been marked as do_not_ripple 
3836
     *  
3837
     * Overridden in ReleaseManagerUtf
3838
     * 
3839
     * @param buildExclusionCollection
3840
     * @param baseline The rtag_id of the release to examine
3841
     * 
3842
     * @exception SQLException
3843
     * @exception Exception
3844
     */
3845
    public void queryBuildExclusions(List<BuildExclusion> buildExclusionCollection, int baseline) throws SQLException, Exception
3846
    {
7044 dpurdie 3847
        mLogger.debug("queryBuildExclusions {}", baseline);
6914 dpurdie 3848
 
3849
        try
3850
        {
3851
            PreparedStatement stmt = mConnection.prepareStatement(
3852
                    "select pv_id, root_pv_id, root_cause" +
3853
                    " from release_manager.do_not_ripple" + 
7176 dpurdie 3854
                    " where rtag_id=?");
6914 dpurdie 3855
            stmt.setFetchSize(1000);
7176 dpurdie 3856
            stmt.setInt(1, baseline);
3857
 
7023 dpurdie 3858
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryBuildExclusions");
6914 dpurdie 3859
 
3860
            while( rset.next() )
3861
            {
7023 dpurdie 3862
                int pvId = rset.mustGetKeyInt("pv_id");
3863
                int rootPvId = rset.getInt("root_pv_id", -1);
3864
                String rootCause = rset.getString("root_cause", null);
6914 dpurdie 3865
 
3866
                // force email notification by using a zero test build instruction
3867
                BuildExclusion buildExclusion = new BuildExclusion(pvId, rootPvId, rootCause, 0);
7032 dpurdie 3868
                buildExclusion.setImported();
6914 dpurdie 3869
                buildExclusionCollection.add(buildExclusion);
3870
            }
3871
 
3872
            rset.close();
3873
            stmt.close();
3874
        }
3875
        catch ( SQLException e )
3876
        {
3877
            handleSQLException(e, "");
3878
        }
3879
    }
3880
 
3881
    /**
7032 dpurdie 3882
     * Execute the Exclude_Indirect_From_Build stored procedure
6914 dpurdie 3883
     *  Note: Execute_Indirect_From_Build will delete matching do_not_ripple
3884
     *        rows prior to an insertion - this is crucial!!
7032 dpurdie 3885
     *        
3886
     * Note: The name 'Execute_Indirect_From_Build' is misleading as it appears to be used for both direct and indirect
3887
     *       exclusions.
3888
     * 
6914 dpurdie 3889
     * @param hasConnection        IN True. Use existing connection and will not commit the operation
3890
     * @param packageVersionId     IN passed to Exclude_Indirect_From_Build
3891
     * @param packageVersion       IN passed to Exclude_Indirect_From_Build
3892
     * @param rtagId               IN passed to Exclude_Indirect_From_Build
3893
     * @param rootPvId             IN passed to Exclude_Indirect_From_Build
3894
     * @param rootCause            IN passed to Exclude_Indirect_From_Build
3895
     * @param rootFile             IN passed to Exclude_Indirect_From_Build
3896
     * @param supercede            IN checks for a row with a matching packageVersionId and rtagId when false
3897
     *                                such a row will prevent the execution of Exclude_Indirect_From_Build
3898
     * @param testBuildInstruction IN will prevent the execution of Exclude_Indirect_From_Build true
3899
     * 
3900
     * @exception SQLException
3901
     * @exception Exception
3902
     */
3903
    public void excludeFromBuild(
3904
            boolean hasConnection, 
3905
            int packageVersionId, 
3906
            String packageVersion, 
3907
            int rtagId,
3908
            String rootPvId, 
3909
            String rootCause,
3910
            String rootFile,
3911
            boolean supercede, Boolean testBuildInstruction) throws SQLException, Exception
3912
    {
7044 dpurdie 3913
        mLogger.debug("excludeFromBuild {}", packageVersionId);
6914 dpurdie 3914
 
3915
        //  If a Test Build, then don't excluded package
3916
        if ( testBuildInstruction )
3917
        {
3918
            return;
3919
        }
3920
 
3921
        if ( mUseDatabase )
3922
        {
3923
            try
3924
            {
3925
                if (!hasConnection)
3926
                    connect();
3927
 
3928
                boolean exist = false;
7032 dpurdie 3929
                boolean dbIsIndirect = false;
3930
                boolean entryIsIndirect = (rootPvId != null);
6914 dpurdie 3931
 
3932
                if ( !supercede )
3933
                {
3934
                    // do not exclude a package already excluded ie let the first build failure count
3935
                    // there is a window of opportunity here, but it is worth doing
3936
                    // scenario 1
3937
                    //      1 this query indicates no build failure exists on this version
3938
                    //      2 another build machine reports a build failure on this version
3939
                    //      3 this is then overridden by this thread
3940
                    // does not matter
3941
                    // doing this works well for the following
3942
                    // scenario 2
3943
                    //      1 this query (run by a slave) indicates no build failure exists on this version
3944
                    //      2 build failure is reported
3945
                    //      3 master build machine detects slave in state waiting
3946
                    //      4 master daemon discovers slave did not deliver artifacts
3947
                    //      5 master daemon is prevented from overriding the build failure
7032 dpurdie 3948
                    //
3949
                    // Another complication
3950
                    //  If this is a direct exclusion (rootPvid) is null and the entry in the table is an indirect exclusion
3951
                    //  then we should delete the indirect exclusion and replace it with a direct exclusion
3952
                    //
7169 dpurdie 3953
                    CallableStatement stmt = mConnection.prepareCall(
3954
                            "select pv_id, root_pv_id from release_manager.do_not_ripple where pv_id=? and rtag_id=?");
3955
                    stmt.setInt(1, packageVersionId);
3956
                    stmt.setInt(2, rtagId);
3957
 
6914 dpurdie 3958
                    ResultSet rset = stmt.executeQuery();
3959
 
3960
                    while( rset.next() )
3961
                    {
3962
                        exist = true;
7032 dpurdie 3963
                        rset.getInt("root_pv_id");
3964
                        dbIsIndirect = ! rset.wasNull();
3965
 
3966
                        // Override an indirect database entry with a direct exclusion
3967
                        if ( dbIsIndirect && ! entryIsIndirect ) {
3968
                            exist = false;
3969
                        }
3970
 
6914 dpurdie 3971
                        break;
3972
                    }
3973
 
3974
                    rset.close();
3975
                    stmt.close();
3976
                }
3977
 
3978
                if ( !exist )
3979
                {
3980
                    CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD(?,?,?,?,?,?,?); end;" );
3981
                    stmt.registerOutParameter( 1, Types.INTEGER);
3982
                    stmt.setInt    ( 2, packageVersionId );
3983
                    stmt.setString ( 3, packageVersion );
3984
                    stmt.setInt    ( 4, rtagId );
3985
                    stmt.setString ( 5, "buildadm" );
3986
                    stmt.setString ( 6, rootPvId);
3987
                    stmt.setString ( 7, rootCause);
3988
                    stmt.setString ( 8, rootFile);
3989
                    stmt.executeUpdate();
3990
                    int result = stmt.getInt( 1 );
3991
 
3992
                    if ( result != 0 )
3993
                    {
3994
                        // flag build failure
7044 dpurdie 3995
                        mLogger.error( "excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned {}",  result );
6914 dpurdie 3996
                        throw new Exception("excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned " + result);
3997
                    }
3998
                    stmt.close();
3999
                    if (!hasConnection )
4000
                        commit();
4001
                }
4002
            }
4003
            catch ( SQLException e )
4004
            {
4005
                handleSQLException(e, "");
4006
            }
4007
            finally
4008
            {
4009
                // this block is executed regardless of what happens in the try block
4010
                // even if an exception is thrown
4011
                // ensure disconnect
4012
                if (!hasConnection )
4013
                    disconnect();
4014
            }
4015
        }
4016
    }
4017
 
4018
    /**
4019
     * Removes an excluded package from the do_not_ripple table, thereby including the package back into the build set.
4020
     * The method does not remove packages that were manually added to the DNR table, as those
4021
     * packages are not in the domain of the buildtool.
4022
     * 
4023
     * @param packageVersionId Packages PVID
4024
     * @param rtagId           The RTAG id of the release to consider
4025
     * 
4026
     * @exception SQLException
4027
     * @exception Exception
4028
     */
4029
 
4030
    public void includeToBuild(int packageVersionId, int rtagId) throws SQLException, Exception
4031
    {
7044 dpurdie 4032
        mLogger.debug("includeToBuild {}", packageVersionId);
6914 dpurdie 4033
        if ( mUseDatabase )
4034
        {
4035
            try
4036
            {
4037
                CallableStatement stmt = mConnection.prepareCall(
4038
                    "delete from release_manager.do_not_ripple " +
7169 dpurdie 4039
                    "  where rtag_id=?" + 
4040
                    "  and pv_id=?" +
6914 dpurdie 4041
                    "  and (root_pv_id is not NULL or root_cause is not NULL or root_file is not NULL)"
4042
                    );
7169 dpurdie 4043
                stmt.setInt(1, rtagId);
4044
                stmt.setInt(2, packageVersionId);
4045
 
6914 dpurdie 4046
                stmt.executeUpdate();
4047
                stmt.close();
4048
            }
4049
            catch ( SQLException e )
4050
            {
4051
                handleSQLException(e, "");
4052
            }
4053
        }
4054
    }
4055
 
4056
 
4057
 
4058
 
4059
    /**queries the RUN_LEVEL table using the rcon_id primary key
4060
     * handles database connection and disconnection
4061
     * returns the current_build_files
4062
     * implements the sequence diagram consume build files 
4063
     *  
4064
     * Used by the Slave Daemon
4065
     * 
4066
     *  @param rcon_id - My release config id
4067
     *  @return The buildFile content. Will be null if none is found
4068
     */
4069
    public String queryBuildFile(int rcon_id) throws SQLException, Exception
4070
    {
4071
        String buildFile = null;
4072
 
7044 dpurdie 4073
        mLogger.debug("queryRunLevel 1 rcon_id {}", rcon_id);
6914 dpurdie 4074
        if ( !mUseDatabase )
4075
        {
4076
            mLogger.info("queryRunLevel 1 !mUseDatabase");
4077
            buildFile = "unit test build file content";
4078
        }
4079
        else
4080
        {
4081
            try
4082
            {
4083
                connect();
7169 dpurdie 4084
                CallableStatement stmt = mConnection.prepareCall("select current_build_files from release_manager.run_level where rcon_id=?");
4085
                stmt.setInt(1, rcon_id);
6914 dpurdie 4086
                ResultSet rset = stmt.executeQuery();
4087
                int rsetSize = 0;
4088
 
4089
                while( rset.next() )
4090
                {
4091
                    rsetSize++;
4092
                    buildFile = rset.getString("current_build_files");
4093
                }
4094
 
4095
                if ( rsetSize > 1 )
4096
                {
7033 dpurdie 4097
                    mLogger.error("queryRunLevel 1 rsetSize > 1");
6914 dpurdie 4098
                    // show stopper
4099
                    throw new Exception("queryRunLevel 1 rsetSize > 1");
4100
                }
4101
 
4102
                rset.close();
4103
                stmt.close();
4104
            }
4105
            catch ( SQLException e )
4106
            {
4107
                handleSQLException(e, "");
4108
            }
4109
            finally
4110
            {
4111
                // this block is executed regardless of what happens in the try block
4112
                // even if an exception is thrown
4113
                // ensure disconnect
4114
                disconnect();
4115
            }
4116
        }
4117
 
4118
        return buildFile;
4119
    }
4120
 
4121
    /** Updates mRunLevelCollection
4122
     *  Removes all elements from mRunLevelCollection, then queries the Database
4123
     *  and re-populates the structure.
4124
     *  
4125
     *  Used to determine which slave daemons the master needs to wait upon.
4126
     *  
4127
     *  Ignores entries that are disabled
4128
     *  Ignore entries that have been 'unlinked' - they have no active machine configuration
4129
     *
4130
     *   @param	rtag_id	- Release Tag
4131
     *  
4132
     *	Used by the Master Daemon 
4133
     * 	Overridden in ReleaseManagerUtf 
4134
     */
4135
    public void queryRunLevel(final int rtag_id) throws SQLException, Exception
4136
    {
7044 dpurdie 4137
        mLogger.debug("queryRunLevel 2 rtag_id {}", rtag_id);
6914 dpurdie 4138
 
4139
        mRunLevelCollection.clear();
4140
 
4141
        try
4142
        {
4143
            connect();
4144
            CallableStatement stmt = mConnection.prepareCall(
4145
                    "SELECT rl.rcon_id," +
4146
                    "  rl.current_run_level," +
4147
                    "  NVL(rl.pause,0) as pause," +
4148
                    "  rc.daemon_mode," +
4149
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4150
                    " FROM release_manager.release_config rc," +
4151
                    "     release_manager.run_level rl" +
7169 dpurdie 4152
                    " WHERE rc.rtag_id = ?" +
6914 dpurdie 4153
                    " AND   rl.rcon_id = rc.rcon_id" +
4154
                    " AND   rc.bmcon_id is not NULL");
4155
            stmt.setFetchSize(20);
7169 dpurdie 4156
            stmt.setInt(1, rtag_id);
7023 dpurdie 4157
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryRunLevel 2");
6914 dpurdie 4158
            int rcon_id = 0;
4159
            int current_run_level = 0;
4160
            String modeString;
4161
            char mode;
4162
            int pause = 0;
4163
            int buildFilePresent = 0;
4164
 
4165
            while( rset.next() )
4166
            {
7023 dpurdie 4167
                rcon_id = rset.mustGetKeyInt("rcon_id");
4168
                modeString = rset.mustGetString("daemon_mode");
6914 dpurdie 4169
                mode = modeString.charAt(0);
7023 dpurdie 4170
                buildFilePresent = rset.getInt("bfPresent",0);
4171
                current_run_level = rset.getInt("current_run_level", BuildState.DB_IDLE.toValue());
6914 dpurdie 4172
 
4173
                //
4174
                //  Pause: null -> 0 == Run
4175
                //         1         == Pause
4176
                //         2         == Disabled
4177
                //
7023 dpurdie 4178
                pause = rset.getInt("pause", 0);
6914 dpurdie 4179
 
4180
                //  Ignore disabled entries
4181
                if ( pause <= 1 )
4182
                {
4183
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, mode, buildFilePresent);
4184
                    mRunLevelCollection.add(runLevel);
4185
                }
4186
            }
4187
 
4188
            rset.close();
4189
            stmt.close();
4190
        }
4191
        catch ( SQLException e )
4192
        {
4193
            handleSQLException(e, "");
4194
        }
4195
        finally
4196
        {
4197
            // this block is executed regardless of what happens in the try block
4198
            // even if an exception is thrown
4199
            // ensure disconnect
4200
            disconnect();
4201
        }
4202
    }
4203
 
4204
    /**
4205
     * Removes all elements and then re-populates mRunLevelCollection
4206
     * 
4207
     * Queries the RM database to determine the run_level of the current daemon.
4208
     * Populates the mRunLevelCollection with the query result set 
4209
     *  
4210
     * Used to determine if the (Slave) thread should still be running
4211
     *  
4212
     * Used by the Slave Daemon 
4213
     * Overridden in ReleaseManagerUtf 
4214
     * 
4215
     * @param rcon_id     Identify the Release_Config table entry for the daemon
4216
     * @param hostname    Name of the host machine
4217
     * @param daemon_mode Specifies the current daemon type
4218
     * 
4219
     * @exception SQLException
4220
     *                      Database connection errors
4221
     *                      Bad SQL statement
4222
     * @exception Exception Too many rows extracted from the database
4223
     *                      Empty(NULL) data in database
4224
     */
4225
    public void querySingleRunLevel(final int rcon_id, String hostname, char daemon_mode) throws SQLException, Exception
4226
    {
7044 dpurdie 4227
        mLogger.debug("querySingleRunLevel rcon_id {}", rcon_id);
6914 dpurdie 4228
        mRunLevelCollection.clear();
4229
 
4230
        try
4231
        {
4232
            connect();
4233
 
4234
            CallableStatement stmt = mConnection.prepareCall(
4235
                    "select rl.rcon_id, "+
4236
                    "  rl.current_run_level,"+
4237
                    "  NVL(rl.pause,0) as pause," +
4238
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4239
                    " from release_manager.run_level rl,"+
4240
                    "   release_manager.release_config rc" +
4241
                    " where rl.rcon_id = rc.rcon_id" +
7169 dpurdie 4242
                    "   AND rc.rcon_id=?" +
6914 dpurdie 4243
                    "   AND rc.bmcon_id is not NULL" +
7169 dpurdie 4244
                    "   AND rc.daemon_mode=?" +
4245
                    "   AND UPPER(rc.daemon_hostname)=UPPER(?)"
6914 dpurdie 4246
                    );
7169 dpurdie 4247
            stmt.setInt(1, rcon_id);
4248
            stmt.setString(2, String.valueOf(daemon_mode));
4249
            stmt.setString(3, hostname);
4250
 
7023 dpurdie 4251
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"querySingleRunLevel");
6914 dpurdie 4252
            int rsetSize = 0;
4253
            int current_run_level = 0;
4254
            int pause = 0;
4255
            int buildFilePresent = 0;
4256
 
4257
            while( rset.next() )
4258
            {
4259
                rsetSize++;
7023 dpurdie 4260
                current_run_level = rset.mustGetInt("current_run_level");
4261
                buildFilePresent = rset.getInt("bfPresent",0);
6914 dpurdie 4262
 
4263
                //
4264
                //  Pause: null -> 0 == Run
4265
                //         1         == Pause
4266
                //         2         == Disabled
4267
                //
7023 dpurdie 4268
                pause = rset.getInt("pause",0);
6914 dpurdie 4269
 
4270
                //  Ignore disabled daemons
4271
                if ( pause <= 1)
4272
                {
4273
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, daemon_mode, buildFilePresent);
4274
                    mRunLevelCollection.add(runLevel);
4275
                }
4276
            }
4277
 
4278
            rset.close();
4279
            stmt.close();
4280
 
4281
            //  Must have no more than one record
4282
            //  Will have none if this daemon is no longer a part of the build set
4283
            //
4284
            if ( rsetSize > 1 )
4285
            {
4286
                //  show stopper
4287
                //  More rows than expected returned from the database
7033 dpurdie 4288
                mLogger.error("querySingleRunLevel rsetSize > 1");
6914 dpurdie 4289
                throw new Exception("querySingleRunLevel rsetSize > 1");
4290
            }
4291
        }
4292
        catch ( SQLException e )
4293
        {
4294
            handleSQLException(e, "");
4295
        }
4296
        finally
4297
        {
4298
            // this block is executed regardless of what happens in the try block
4299
            // even if an exception is thrown
4300
            // ensure disconnect
4301
            disconnect();
4302
        }
4303
    }
4304
 
4305
    /**Queries the RUN_LEVEL_SCHEDULE table to determine if we can proceed
4306
     * <br>Will not proceed if:
4307
     *      <br>- Inside a scheduled downtime
4308
     *      <br>- Indefinite pause present
4309
     * 
4310
     * <br>Should delete rows with a non NULL indefinite pause (but doesn't appear too)
4311
     *  
4312
     * <br>Assumes connection to database has been established
4313
     * 
4314
     * @param   resumeTime.value  Returns date-time when daemon can run again 
4315
     * 
4316
     * @return  False: if a row in the query result set indicates build service downtime is scheduled
4317
     *      <br>False: if a row in the query result set has a non NULL indefinite_pause
4318
     */
4319
    public boolean queryRunLevelSchedule(MutableDate resumeTime) throws SQLException, Exception
4320
    {
4321
        mLogger.debug("queryRunLevelSchedule");
4322
        boolean retVal = true;
4323
 
4324
        if ( mUseDatabase )
4325
        {
4326
            //
4327
            //  Clean up the run_level_schedule table by deleting out of date entries
4328
            //
4329
            try
4330
            {
4331
                CallableStatement stmt = mConnection.prepareCall( "BEGIN PK_BUILDAPI.DELETE_OUT_OF_DATE_SCHEDULE;   END;" );
4332
                stmt.executeUpdate();
4333
                stmt.close();
4334
                commit();
4335
            }
4336
            catch ( SQLException e )
4337
            {
4338
                handleSQLException(e, ":1");
4339
            }
4340
 
4341
            try
4342
            {
4343
                //  Extract info from the database
4344
                //
4345
                CallableStatement stmt = mConnection.prepareCall(
4346
                        "select scheduled_pause, scheduled_resume, repeat, indefinite_pause" + 
4347
                        " from release_manager.run_level_schedule");
4348
                ResultSet rset = stmt.executeQuery();
4349
                Date now = new Date();
4350
 
4351
                //
4352
                //  Scan the database information and determine if there is any reason
4353
                //  to pause. Terminate the loop on the first excuse to pause
4354
                //  as indefinite pause may have multiple (lots) of entries in the data
4355
                //  base.
4356
                //
4357
                while( retVal && rset.next() )
4358
                {
4359
                    //
4360
                    //  Examine the current row from the data base
4361
                    //  Expect one of two forms:
4362
                    //    1) scheduled_pause
4363
                    //       Must also have a scheduled_resume and a repeat
4364
                    //    2) indefinite_pause
4365
                    //
4366
 
4367
                    //  Look for scheduled_pause style of entry
4368
                    //
4369
                    Timestamp sp = rset.getTimestamp("scheduled_pause");
4370
                    if ( sp != null )
4371
                    {
4372
                        Date scheduledPause = new Date( sp.getTime() );
4373
                        Timestamp sr = rset.getTimestamp("scheduled_resume");
4374
 
4375
                        if ( sr != null )
4376
                        {
4377
                            Date scheduledResume = new Date( sr.getTime() );
4378
                            int repeat = rset.getInt("repeat");
7176 dpurdie 4379
                            mLogger.debug("queryRunLevelSchedule repeat {}", repeat);
6914 dpurdie 4380
 
4381
                            //
4382
                            //  Have scheduled_pause and scheduled_resume
4383
                            //  Examine the repeat field and determine how these are used
4384
                            //  Supported repeat:
4385
                            //      0:Once Only
4386
                            //      1:Daily           Year, Month and Day information is ignored
4387
                            //      7:Weekly          Only day of week is utilized
4388
                            //
4389
                            if ( !rset.wasNull() )
4390
                            {
4391
                                GregorianCalendar startOfDowntime = new GregorianCalendar();
4392
                                GregorianCalendar endOfDowntime = new GregorianCalendar();
4393
                                GregorianCalendar clock = new GregorianCalendar();
4394
 
4395
                                switch( repeat )
4396
                                {
4397
                                    case 0:
4398
                                        // Once Only
4399
                                        // Simple check between start and end date-times
4400
                                        if ( scheduledPause.before(now) && scheduledResume.after(now) )
4401
                                        {
4402
                                            mLogger.warn("queryRunLevelSchedule one off scheduled downtime");
4403
                                            resumeTime.value = scheduledResume;
4404
                                            retVal = false;
4405
                                        }
4406
                                        break;
4407
 
4408
                                    case 1:
4409
 
4410
                                        //  Daily
4411
                                        //  Create start and end times, then massage some fields
4412
                                        //  to reflect todays date.
4413
                                        //  Use start and end times from scheduled_pause and scheduled_resume
4414
                                        //
4415
 
4416
                                        startOfDowntime.setTime(scheduledPause);
4417
                                        endOfDowntime.setTime(scheduledResume);
4418
                                        clock.setTime(now);
4419
 
4420
                                        // Force date fields to todays date
4421
                                        endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4422
                                        startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4423
 
4424
                                        if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4425
                                        {
4426
                                            mLogger.warn("queryRunLevelSchedule daily scheduled downtime");
4427
                                            resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4428
                                            retVal = false;
4429
                                        }
4430
                                        break;
4431
 
4432
                                    case 7:
4433
 
4434
                                        // Weekly
4435
                                        // Create start and end times, then massage some fields
4436
                                        // to reflect todays date.
4437
                                        // Use DayOfWeek and time from scheduled_pause
4438
                                        // Use time from scheduled_resume
4439
                                        //
4440
                                        startOfDowntime.setTime(scheduledPause);
4441
                                        endOfDowntime.setTime(scheduledResume);
4442
                                        clock.setTime(now);
4443
 
4444
                                        // Only interested in one day of the week
4445
                                        if ( startOfDowntime.get(Calendar.DAY_OF_WEEK) == clock.get(Calendar.DAY_OF_WEEK) )
4446
                                        {
4447
                                            endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4448
                                            startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4449
 
4450
                                            if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4451
                                            {
4452
                                                mLogger.warn("queryRunLevelSchedule weekly scheduled downtime");
4453
                                                resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4454
                                                retVal = false;
4455
                                            }
4456
                                        }
4457
                                        break;
4458
 
4459
                                   default:
4460
                                       //
4461
                                       //   Unexpected value
4462
                                       break;
4463
                                }
4464
                            }
4465
                        }
4466
                    }
4467
 
4468
                    //
4469
                    //  Look for indefinite_pause style of entry
4470
                    //  Note: due to an implementation error there may be many
4471
                    //        rows that match. We only need one. The scan will
4472
                    //        be terminated if we find any
4473
                    //  
4474
                    //
4475
                    String ip = rset.getString("indefinite_pause");
4476
                    if ( ip != null )
4477
                    {
4478
                        // indefinite pause is non null
4479
                        mLogger.warn("queryRunLevelSchedule indefinite pause");
4480
                        GregorianCalendar clock = new GregorianCalendar();
4481
                        clock.setTime(now);
4482
                        // wait a minute
4483
                        resumeTime.value.setTime(clock.getTimeInMillis() + 60000);
4484
                        retVal = false;
4485
                    }
4486
                }
4487
 
4488
                rset.close();
4489
                stmt.close();
4490
            }
4491
            catch ( SQLException e )
4492
            {
4493
                handleSQLException(e, ":2");
4494
            }
4495
        }
4496
 
7176 dpurdie 4497
        mLogger.debug("queryRunLevelSchedule returning {}", retVal);
6914 dpurdie 4498
        return retVal;
4499
    }
4500
 
4501
    /**persists the runLevel in the RUN_LEVEL table for the rcon_id primary key
4502
     * 
4503
     * Overridden in the UTF
4504
     * 
4505
     * @param   rcon_id         Identifies the Release Connection (daemon)
4506
     * @param   runLevel        The run level to set
4507
     * 
4508
     */
4509
    public void updateCurrentRunLevel(final int rcon_id, final int runLevel) throws SQLException, Exception
4510
    {
4511
        mLogger.debug("updateCurrentRunLevel");
4512
 
4513
        try
4514
        {
4515
            connect();
4516
 
7044 dpurdie 4517
            mLogger.warn("updateCurrentRunLevel: Set Runlevel:{}, rconId:{}", runLevel, rcon_id);
7169 dpurdie 4518
            PreparedStatement stmt = mConnection.prepareCall(
4519
                    "update release_manager.run_level set current_run_level=?, keep_alive=SYSDATE where rcon_id=?");
4520
            stmt.setInt(1, runLevel);
4521
            stmt.setInt(2, rcon_id);
6914 dpurdie 4522
            stmt.executeUpdate();
4523
            stmt.close();
4524
 
4525
            mLogger.info("updateCurrentRunLevel: committing");
4526
            commit();
4527
            mLogger.info("updateCurrentRunLevel: committed");
4528
        }
4529
        catch ( SQLException e )
4530
        {
4531
            handleSQLException(e, "");
4532
        }
4533
        finally
4534
        {
4535
            // this block is executed regardless of what happens in the try block
4536
            // even if an exception is thrown
4537
            // ensure disconnect
4538
            disconnect();
4539
        }
4540
 
4541
    }
4542
 
4543
    /** Report the current build plan
4544
     *  This is only for display purposes
4545
     *  Assume a connection has been established. Will not commit if the operation is covered by the Mutex
4546
     *  
4547
     * @param mRtagId - Release we are building
4548
     * @param mBuildOrder - Ordered list of PackageVersions that we plan to build
4549
     * @throws Exception 
4550
     * @throws SQLException 
4551
     */
7088 dpurdie 4552
    public void reportPlan(int mRtagId, ArrayList<PlannedPackage> mBuildOrder) throws SQLException, Exception {
7044 dpurdie 4553
        mLogger.debug("reportPlan {}", mRtagId);
6914 dpurdie 4554
 
4555
        if ( mUseDatabase )
4556
        {
4557
            try
4558
            {
7082 dpurdie 4559
                Iterator<PlannedPackage> it = mBuildOrder.iterator();
6914 dpurdie 4560
                int fragment = 0;
4561
                CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.set_build_plan(?,?,?)" );
4562
 
4563
                do {
4564
                    //
4565
                    // Generate a comma separated list of PVIDs
4566
                    // Limit the length of the string since we can only pump 4000 chars into a string
4567
                    // Allow 10 chars per PV_ID
4568
                    //
4569
                    StringBuilder pvList = new StringBuilder();
4570
                    String joiner = "";
4571
 
4572
                    while ( pvList.length() < 3000  && it.hasNext() )
4573
                    {
7082 dpurdie 4574
                        PlannedPackage p = it.next();
6914 dpurdie 4575
                        pvList.append(joiner);
7082 dpurdie 4576
                        pvList.append(p.mPkg.mId);
6914 dpurdie 4577
                        joiner = ",";
4578
                    }
4579
 
4580
                    //  Terminate if we have nothing to add and its not the first pass
4581
                    if (pvList.length() <= 0 && fragment != 0)
4582
                    {
4583
                        break;
4584
                    }
4585
 
4586
                    //
4587
                    //  Insert data - one fragment at a time
4588
                    //
4589
                    stmt.setInt    ( 1, mRtagId );
4590
                    stmt.setInt    ( 2, fragment );
4591
                    stmt.setString ( 3, pvList.toString() );
4592
                    stmt.executeUpdate();
4593
                    fragment++;
4594
 
4595
                } while(true);
4596
 
4597
                stmt.close();
4598
 
4599
                //  Commit only if not covered by the Mutex
4600
                if ( ! mDoNotCommit )
4601
                    commit();
4602
            }
4603
            catch ( SQLException e )
4604
            {
4605
                handleSQLException(e, "");
4606
            }
4607
            finally
4608
            {
4609
                // this block is executed regardless of what happens in the try block
4610
                // even if an exception is thrown
4611
            }
4612
        }
4613
    }
4614
 
4615
    public void updateBuildDuration(int pvId, int duration) throws Exception {
7044 dpurdie 4616
        mLogger.debug("updateBuildDuration {}:{}", pvId, duration);
6914 dpurdie 4617
        if ( mUseDatabase )
4618
        {
4619
            try
4620
            {
4621
                connect();
4622
 
7176 dpurdie 4623
                PreparedStatement stmt = mConnection.prepareStatement("update release_manager.package_versions set BUILD_TIME = ? where pv_id = ?");
6914 dpurdie 4624
                stmt.setLong( 1,duration );
4625
                stmt.setLong( 2,pvId );
4626
                stmt.executeUpdate();
4627
                stmt.close();
4628
                commit();
4629
            }
4630
            catch ( SQLException e )
4631
            {
4632
                handleSQLException(e, "");
4633
            }
4634
            finally
4635
            {
4636
                disconnect();
4637
            }
4638
        }
4639
    }
4640
 
4641
    /**  Set RippleStop flag to 'w' for waiting
4642
     *  Indicated that the build system will Ripple the package, when the user confirms that it can be done
4643
     *  Assume database connection has been established
4644
     * @param mRtagId 
4645
     * 
4646
     * @param pkg - Package being processed
4647
     * @throws Exception 
4648
     */
4649
    public void setRippleStopWait(int mRtagId, Package pkg) throws Exception {
4650
 
4651
        // Use a stored procedure as it will also do logging
4652
        mLogger.debug("setRippleStopWait");
4653
        if ( mUseDatabase )
4654
        {
4655
            try
4656
            {
4657
                // "BEGIN  PK_PACKAGE.Set_Ripple_Stop( :PV_ID, :RTAG_ID, :USER_ID, :RSTATE );  END;"
4658
 
4659
                CallableStatement stmt = mConnection.prepareCall( "BEGIN  PK_PACKAGE.Set_Ripple_Stop( ?, ?, ?, 'w' );  END;" );
4660
                stmt.setInt(1, pkg.mId);        // PVID
4661
                stmt.setInt(2, mRtagId);        // RTAG ID 
4662
                stmt.setInt(3, 3768);           // USER ID - buildadm ( Yes I know its ugly )
4663
                stmt.executeUpdate();
4664
                stmt.close();
4665
            }
4666
            catch ( SQLException e )
4667
            {
4668
                handleSQLException(e, "");
4669
            }
4670
        }
4671
 
4672
    }
4673
 
7169 dpurdie 4674
    /** Reset the dumpPlan request
4675
     *  Assume that we have a database connection
7176 dpurdie 4676
     *  @param mRtagId - Identify the target release
4677
     *  @throws Exception 
7169 dpurdie 4678
     */
4679
    public void resetPlanControl(int mRtagId) throws Exception {
4680
        mLogger.debug("resetPlanControl {}", mRtagId);
4681
 
4682
        if ( mUseDatabase )
4683
        {
4684
            try
4685
            {
4686
                CallableStatement stmt = mConnection.prepareCall(
4687
                        "UPDATE release_manager.release_tags SET PLAN_DROP = 'N' WHERE rtag_id  = ?" );
4688
                stmt.setInt(1, mRtagId);
4689
                stmt.executeUpdate();
4690
                stmt.close();
7176 dpurdie 4691
 
4692
                //  Commit only if not covered by the Mutex
4693
                if ( ! mDoNotCommit )
4694
                    commit();
4695
 
7169 dpurdie 4696
            }
4697
            catch ( SQLException e )
4698
            {
4699
                handleSQLException(e, "");
4700
            }
4701
        }
4702
 
7176 dpurdie 4703
        mLogger.debug("resetPlanControl {} Done", mRtagId);        
7169 dpurdie 4704
    }
4705
 
7333 dpurdie 4706
    /** Insert Build Information. Two items at the moment:
4707
     *   * The list of all platforms that the package 'can' be built for
4708
     *   * The list of all pltaforms the package was built for
4709
     * @param bIsaTestBuild - True. Is a Test Build 
4710
     * @param mReporting
4711
     * @param mBuildInfo
4712
     * @throws Exception 
4713
     */
4714
    public void insertBuildInfo(boolean bIsaTestBuild, ReportingData mReporting, BuildInfo mBuildInfo) throws Exception
4715
    {
4716
        if ( mUseDatabase )
4717
        {
4718
            String result = null;
4719
            try
4720
            {
4721
                connect();
4722
 
4723
                if ( ! bIsaTestBuild )
4724
                {
4725
                    // Platforms that the package can be built for
4726
                    // This is a property of the package-version
4727
                    //
4728
                    StringAppender platformList = new StringAppender(",");
4729
                    platformList.append(mBuildInfo.mPlatforms.iterator());
4730
 
4731
 
4732
                    CallableStatement stmt1 = mConnection.prepareCall( "BEGIN ? :=  PK_BUILDAPI.insert_pv_platforms( ?, ?, ? );  END;" );
4733
                    stmt1.registerOutParameter( 1, Types.VARCHAR);
4734
                    stmt1.setInt(2, mReporting.packageVersionId);    // PVID
4735
                    stmt1.setString(3, platformList.toString());     // Platforms we can build for 
4736
                    stmt1.setInt(4, 1);                              // Clear before add
4737
                    stmt1.executeUpdate();
4738
                    result = stmt1.getString(1);
4739
                    stmt1.close();
4740
 
4741
                    if (result != null && result.length() > 0 )                 {
4742
                        mLogger.warn("Unknown platforms: {}", result);
4743
                    }
4744
                }
4745
 
4746
                // Platforms that the package was built for
4747
                // This is a property of the Build Instance and may differ from build to build
4748
                //
4749
                StringAppender platformBuildList = new StringAppender(",");
4750
                platformBuildList.append(mBuildInfo.mBuildPlatforms.iterator());
4751
 
4752
                CallableStatement stmt2 = mConnection.prepareCall( "BEGIN ? := PK_BUILDAPI.insert_bi_platforms( ?, ?, ? );  END;" );
4753
                stmt2.registerOutParameter( 1, Types.VARCHAR);
4754
                stmt2.setInt(2, mReporting.buildId);             // Build Id
4755
                stmt2.setString(3, platformBuildList.toString());     // Platforms we can build for 
4756
                stmt2.setInt(4, 1);                             // Clear before add
4757
                stmt2.executeUpdate();
4758
                result = stmt2.getString(1);
4759
                stmt2.close();
4760
                if (result != null && result.length() > 0 )                 {
4761
                    mLogger.warn("Unknown build platforms: {}", result);
4762
                }
4763
 
4764
                commit();
4765
            }
4766
            catch ( SQLException e )
4767
            {
4768
                handleSQLException(e, "");
4769
            }
4770
            finally
4771
            {
4772
                // this block is executed regardless of what happens in the try block
4773
                // even if an exception is thrown
4774
                // ensure disconnect
4775
                disconnect();
4776
            }
4777
        }        
4778
    }
4779
 
7489 dpurdie 4780
    /** Potentially take a snapshot of the current release
4781
     *  Assumes that the last build-plan was an empty plan. ie: Nothing to build
4782
     *  Will check that there are no build errors
4783
     *  It will ignore packages that cannot be built as they have no BuildStandard
4784
     *  
4785
     * @param mRtagId   - Release to process
4786
     * @throws Exception 
4787
     * @throws SQLException 
4788
     */
4789
    public void takeSnapshot(int mRtagId) throws SQLException, Exception {
4790
        int buildErrors = 0;
4791
        try
4792
        {
4793
            connect();
4794
 
4795
            //  Determine if there are any packages that have been excluded from the build
4796
            //
4797
            mLogger.debug("takeSnapshot {}", mRtagId);
4798
            PreparedStatement stmt0 = mConnection.prepareStatement(
4799
                    "select count(*) as count from do_not_ripple dnr, package_build_info pbi where rtag_id = ? and dnr.pv_id = pbi.pv_id");
4800
            stmt0.setFetchSize(1000);
4801
            stmt0.setInt(1, mRtagId);
4802
 
4803
            RmResultSet rset = new RmResultSet(stmt0.executeQuery(),"queryBuildExclusions");
4804
 
4805
            if ( rset.next() )             {
4806
                buildErrors = rset.mustGetKeyInt("count");
4807
            } else {
4808
                buildErrors = 1;
4809
            }
4810
 
4811
            rset.close();
4812
            stmt0.close();
4813
 
4814
            if (buildErrors == 0 )
4815
            {
4816
                //  No Build errors
4817
                //  Take a snapshot, but not if its the same as the last one
4818
                //
4819
                CallableStatement stmt1 = mConnection.prepareCall( "call PK_RELEASE.TAKE_SNAPSHOT(?,?,?,?)" );
4820
                stmt1.setInt( 1, mRtagId );
4821
                stmt1.setInt( 2, 0 );
4822
                stmt1.setInt( 3, 3768 );               // USER ID - buildadm ( Yes I know its ugly )
4823
                stmt1.registerOutParameter( 4, Types.INTEGER);
4824
                stmt1.executeUpdate();
4825
                int newRtagId = stmt1.getInt( 4 );
4826
                stmt1.close();
4827
 
4828
                if (newRtagId > 0 ) {
4829
                    mLogger.warn("Snapshot taken: {} New: {}", mRtagId, newRtagId);
4830
                }
4831
            }
4832
 
4833
 
4834
        }
4835
        catch ( SQLException e )
4836
        {
4837
            handleSQLException(e, "");
4838
        }
4839
        finally
4840
        {
4841
            // this block is executed regardless of what happens in the try block
4842
            // even if an exception is thrown
4843
            // ensure disconnect
4844
            disconnect();
4845
        }        
4846
    }
4847
 
6914 dpurdie 4848
}
4849