Subversion Repositories DevTools

Rev

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