Subversion Repositories DevTools

Rev

Rev 7093 | 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();
1112
                CallableStatement stmt = mConnection.prepareCall("begin ? := PK_RMAPI.new_build_instance(?,?,?); end;");
1113
                stmt.registerOutParameter( 1, Types.INTEGER);
1114
                stmt.setLong( 2,rtagId );
1115
                stmt.setLong( 3,pvId );
1116
                stmt.setString( 4,reason.toString() );
1117
                stmt.executeUpdate();
1118
                buildId = stmt.getInt( 1 );
1119
 
7048 dpurdie 1120
                mLogger.warn("createBuildInstance: Build Instance ID: {}", buildId);
6914 dpurdie 1121
 
1122
                stmt.close();
1123
                commit();
1124
            }
1125
            catch ( SQLException e )
1126
            {
1127
                handleSQLException(e, "");
1128
            }
1129
            finally
1130
            {
1131
                // this block is executed regardless of what happens in the try block
1132
                //      even if an exception is thrown
1133
                //      ensure disconnect
1134
                disconnect();
1135
            }
1136
        }
1137
        return buildId;
1138
    }
1139
 
1140
    /**
1141
     * Update the Build_Instance table.
1142
     * <br>Record the state of the current build in the database
1143
     * 
1144
     * @param buildId  - Build ID of build
1145
     * @param pvId     - PV_ID of the build
1146
     * @param result   - Outcome  of the build
1147
     * 
1148
     * Returns the internal error code. <0 == error
1149
     * 
1150
     * @throws throws SQLException, Exception 
1151
     * 
1152
     */
1153
    public int updateBuildInstance(int buildID, int pvId, BuildResult result) throws SQLException, Exception
1154
    {
1155
        int rv = 0;
1156
 
7048 dpurdie 1157
        mLogger.debug("updateBuildInstance {}:{}:{}", buildID, pvId, result);
6914 dpurdie 1158
        if ( mUseDatabase )
1159
        {
1160
            try
1161
            {
1162
                connect();
1163
 
1164
                String sql = "begin ? := PK_RMAPI.update_build_instance(?,?,?); end;";
1165
 
1166
                CallableStatement stmt = mConnection.prepareCall(sql);
1167
                stmt.registerOutParameter( 1, Types.INTEGER);
1168
                stmt.setLong( 2,buildID );
1169
                stmt.setLong( 3,pvId );
1170
                stmt.setString( 4,result.toString() );
1171
                stmt.executeUpdate();
1172
                rv = stmt.getInt( 1 );
1173
 
7048 dpurdie 1174
                mLogger.warn("updateBuildInstance: Result: {}", rv);
6914 dpurdie 1175
 
1176
                stmt.close();
1177
                commit();
1178
            }
1179
            catch ( SQLException e )
1180
            {
1181
                handleSQLException(e, "");
1182
            }
1183
            finally
1184
            {
1185
                // this block is executed regardless of what happens in the try block
1186
                //      even if an exception is thrown
1187
                //      ensure disconnect
1188
                disconnect();
1189
            }
1190
        }
1191
        return rv;
1192
    }
1193
 
1194
    /**
1195
     * Insert Test Results into Release Manager
1196
     * Manage connection and disconnection
1197
     * 
1198
     * @param buildId
1199
     * @param btr
1200
     * @throws Exception, SQLException 
1201
     */
1202
    public void insertTestResults(int buildId, BuildTestResults btr) throws Exception, SQLException
1203
    {
1204
        if (buildId <= 0)
1205
        {
1206
            mLogger.warn("insertTestResults: Invalid build Id");
1207
            return;
1208
        }
1209
 
1210
        if ( !mUseDatabase || !btr.mResultsFound )
1211
        {
1212
            return;
1213
        }
1214
 
7048 dpurdie 1215
        mLogger.warn("insertTestResults: {}, Number:{}", buildId, btr.mTestResults.size() );
6914 dpurdie 1216
        try
1217
        {
1218
            connect();
1219
            String sql = "BEGIN ? := PK_RMAPI.insert_test_run(?, ?, ?, ?, ?, ?, ?);end;";
1220
            CallableStatement stmt = mConnection.prepareCall(sql);
1221
            stmt.registerOutParameter( 1, Types.INTEGER);
1222
            stmt.setLong(2, buildId);
1223
            Clob myClob = mConnection.createClob();
1224
 
1225
            for (int ii = 0; ii < btr.mTestResults.size(); ii++)
1226
            {
1227
                //System.out.println("Data: " +data.testResults.get(ii).toString());
1228
 
1229
                BuildTestResults.testResultData td = btr.mTestResults.get(ii);
1230
                if (td.platform != null)
1231
                {
1232
                    stmt.setString(3, td.testName);
1233
                    stmt.setString(4, td.outcome);
1234
                    stmt.setString(5, td.platform);
1235
                    stmt.setString(6, td.type);
1236
                    if (td.duration ==  null) {
1237
                        stmt.setNull(7, Types.NUMERIC);
1238
                    } else {
1239
                        stmt.setLong  (7, td.duration);
1240
                    }
1241
 
1242
                    // Insert CLOB data, or a null
1243
                    if (td.message == null)
1244
                    {
1245
                        stmt.setNull(8,Types.CLOB);
1246
                    }
1247
                    else
1248
                    {
1249
                        myClob.truncate(0);
1250
                        myClob.setString(1, td.message);
1251
                        stmt.setClob(8, myClob);
1252
                    }
1253
 
1254
                    stmt.execute();
1255
                    int rv = stmt.getInt( 1 );
1256
 
1257
                    if (rv != 1)
1258
                    {
7033 dpurdie 1259
                        mLogger.error("insertTestResults show stopper. Insert error");
6914 dpurdie 1260
                        throw new Exception("insertTestResults show stopper. Insert error");
1261
                    }
1262
                }
1263
            }
1264
            stmt.close();
1265
 
1266
        }
1267
        catch ( SQLException e )
1268
        {
1269
            handleSQLException(e, "");
1270
        }
1271
        finally
1272
        {
1273
            // this block is executed regardless of what happens in the try block
1274
            // even if an exception is thrown
1275
            // ensure disconnect
1276
            disconnect();
1277
        }
1278
    }
1279
 
1280
    /**executes the get_daemon_inst function with the passed parameters
7023 dpurdie 1281
     * @param   di          - Daemon Instruction Control Data Information
1282
     * 
6914 dpurdie 1283
     * @return  true if an instruction exists - for use in a while loop
1284
     */
7023 dpurdie 1285
    public boolean getDaemonInst(DaemonInstruction di ) throws SQLException, Exception
6914 dpurdie 1286
    {
7048 dpurdie 1287
        mLogger.debug("getDaemonInst {}", di.instruction);
6914 dpurdie 1288
        boolean retVal = false;
1289
 
1290
        if ( mUseDatabase )
1291
        {
1292
            try
1293
            {
7023 dpurdie 1294
                CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_BUILDAPI.GET_DAEMON_INST(?,?,?,?,?,?,?); end;" );
6914 dpurdie 1295
                stmt.registerOutParameter(1, Types.INTEGER);
1296
                stmt.registerOutParameter(3, Types.INTEGER);
1297
                stmt.registerOutParameter(4, Types.INTEGER);
1298
                stmt.registerOutParameter(5, Types.INTEGER);
1299
                stmt.registerOutParameter(6, Types.INTEGER);
1300
                stmt.registerOutParameter(7, Types.INTEGER);
7023 dpurdie 1301
                stmt.setInt(2, di.rtag_id );
1302
                stmt.setInt( 3, di.instruction );
1303
                stmt.setInt( 4, di.opCode );
1304
                stmt.setInt(8, di.expired ? 1 : 0);
6914 dpurdie 1305
                stmt.execute();
1306
                int result = stmt.getInt( 1 );
1307
 
1308
                if ( result == 1 )
1309
                {
1310
                    retVal = true;
7023 dpurdie 1311
                    di.instruction = stmt.getInt( 3 );
1312
                    di.pvId = stmt.getInt( 5 );
1313
                    di.userId = stmt.getInt( 6 );
6914 dpurdie 1314
 
1315
                    //
1316
                    //  Convert userId into an email address
1317
                    //
1318
                    CallableStatement stmt1 = mConnection.prepareCall(
7023 dpurdie 1319
                            "select user_email from release_manager.users where user_id=" + di.userId);
6914 dpurdie 1320
                    ResultSet rset1 = stmt1.executeQuery();
1321
 
1322
                    while( rset1.next() )
1323
                    {
7023 dpurdie 1324
                        di.userEmail = rset1.getString("user_email");
6914 dpurdie 1325
                        if (rset1.wasNull())
1326
                        {
7023 dpurdie 1327
                            di.userEmail = "";
6914 dpurdie 1328
                        }
1329
                    }
1330
 
1331
                    rset1.close();
1332
                    stmt1.close();
1333
 
1334
                }
1335
 
1336
                stmt.close();
1337
 
1338
            }
1339
            catch ( SQLException e )
1340
            {
1341
                handleSQLException(e, "");
1342
            }
1343
        }
1344
        return retVal;
1345
    }
7023 dpurdie 1346
 
6914 dpurdie 1347
    /** Mark a Daemon Instruction as in-progress
1348
     *  Assumes that a database connection has been established
1349
     *  Assumes that the connection is within a Mutex session and the database commit will be done elsewhere
1350
     *  
1351
     *  @param  instruction - PVID of the daemon instruction to process
1352
     */
1353
    public void markDaemonInstInProgress(final int instruction) throws SQLException, Exception
1354
    {
7048 dpurdie 1355
        mLogger.debug("markDaemonInstInProgress {}", instruction);
6914 dpurdie 1356
 
1357
        if ( mUseDatabase )
1358
        {
1359
            try
1360
            {
1361
                CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.MARK_DAEMON_INST_IN_PROGRESS(?)" );
1362
                stmt.setInt( 1, instruction );
1363
                stmt.executeUpdate();
1364
                stmt.close();
1365
            }
1366
            catch ( SQLException e )
1367
            {
1368
                handleSQLException(e, "");
1369
            }
1370
        }
1371
    }
1372
 
1373
    /** Mark a Daemon Instruction as completed
1374
     *  Will establish (and release) a database connection if non is currently open
1375
     *  Will commit the change - unless commits have been disabled within a Mutex session
1376
     *  
1377
     *  @param  instruction - PVID of Daemon Instruction to process
1378
     */
1379
    public void markDaemonInstCompleted(final int instruction) throws SQLException, Exception
1380
    {
7048 dpurdie 1381
        mLogger.debug("markDaemonInstCompletedConnect {}", instruction);
6914 dpurdie 1382
        boolean connectionCreated = false;
1383
 
1384
        try
1385
        {
1386
            if (! mIsConnected)
1387
            {
1388
                connect();
1389
                connectionCreated = true;
1390
            }
1391
 
1392
            if ( mUseDatabase )
1393
            {
1394
                try
1395
                {
1396
                    CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.MARK_DAEMON_INST_COMPLETED(?)" );
1397
                    stmt.setInt( 1, instruction );
1398
                    stmt.executeUpdate();
1399
                    stmt.close();
1400
                }
1401
                catch ( SQLException e )
1402
                {
1403
                    handleSQLException(e, "");
1404
                }
1405
            }
1406
 
1407
            if ( ! mDoNotCommit )
1408
            {
1409
                commit();
1410
            }
1411
        }
1412
        catch ( SQLException e )
1413
        {
1414
            handleSQLException(e, "");
1415
        }
1416
        finally
1417
        {
1418
            // this block is executed regardless of what happens in the try block
1419
            // even if an exception is thrown
1420
            // ensure disconnect
1421
            if (connectionCreated)
1422
            {
1423
                disconnect();
1424
            }
1425
        }
1426
    }
1427
 
1428
    /**
1429
     * Determine the RTAG_ID associated with a given SBOM
1430
     * Sets up mRtagId and mSbomId 
1431
     *  
1432
     * Overridden in ReleaseManagerUtf
1433
     * 
1434
     * @param sbom_id An sbom_id to process
1435
     * 
1436
     * @return The SBOM's RTAG_ID, or zero if none was found
1437
     * @exception SQLException
1438
     */
1439
    public int queryRtagIdForSbom(int sbom_id) throws SQLException
1440
    {
1441
        int rtagId = 0;
1442
 
1443
        CallableStatement stmt = mConnection.prepareCall("select b.rtag_id_fk from deployment_manager.boms b where b.bom_id=" + sbom_id);
1444
        ResultSet rset = stmt.executeQuery();
1445
        while( rset.next() )
1446
        {
1447
            rtagId = rset.getInt("rtag_id_fk");
1448
        }
1449
        rset.close();
1450
        stmt.close();
1451
 
1452
        return rtagId;
1453
     }
1454
 
1455
 
1456
    /**In daemon mode
1457
     * Returns a concatenation of the proj_name and rtag_name 
1458
     *  
1459
     * In escrow mode
1460
     * Returns a concatenation of the proj_name, branch_name, bom_version and bom_lifecycle 
1461
     *  
1462
     * Overridden in ReleaseManagerUtf 
1463
     */
1464
    public String queryBaselineName(int baseline) throws SQLException, Exception
1465
    {
7048 dpurdie 1466
        mLogger.debug("queryBaselineName {}", mDaemon);
6914 dpurdie 1467
        StringBuilder retVal = new StringBuilder();
1468
 
1469
        String sql = "";
1470
 
1471
        if ( mDaemon )
1472
        {
1473
            sql = "select p.proj_name, rt.rtag_name" +
1474
                  " from release_manager.projects p, release_manager.release_tags rt" +
1475
                  " where rt.rtag_id=" + baseline + " and p.proj_id=rt.proj_id";
1476
        }
1477
        else
1478
        {
1479
            sql = "select dp.proj_name, br.branch_name, b.bom_version, b.bom_lifecycle" +
1480
                  " from deployment_manager.dm_projects dp, deployment_manager.branches br, deployment_manager.boms b" +
1481
                  " where b.bom_id=" + baseline + " and br.branch_id=b.branch_id and dp.proj_id=br.proj_id";
1482
        }
1483
 
1484
        try
1485
        {
1486
            CallableStatement stmt = mConnection.prepareCall(sql);
1487
            ResultSet rset = stmt.executeQuery();
1488
 
1489
            while( rset.next() )
1490
            {
1491
                String proj_name = rset.getString("proj_name");
1492
 
1493
                if ( proj_name != null )
1494
                {
1495
                    retVal.append(proj_name);
1496
                }
1497
 
1498
                if ( mDaemon )
1499
                {
1500
                    String rtag_name = rset.getString("rtag_name");
1501
 
1502
                    if ( rtag_name != null )
1503
                    {
1504
                        retVal.append(" > ").append(rtag_name);
1505
                    }
1506
                }
1507
                else
1508
                {
1509
                    String branch_name = rset.getString("branch_name");
1510
 
1511
                    if ( branch_name != null )
1512
                    {
1513
                        retVal.append(" > ").append(branch_name);
1514
                    }
1515
 
1516
                    String bom_version = rset.getString("bom_version");
1517
 
1518
                    if ( bom_version != null )
1519
                    {
1520
                        retVal.append(" ").append(bom_version);
1521
                    }
1522
 
1523
                    String bom_lifecycle = rset.getString("bom_lifecycle");
1524
 
1525
                    if ( bom_lifecycle != null )
1526
                    {
1527
                        retVal.append(".").append(bom_lifecycle);
1528
                    }
1529
                }
1530
            }
1531
 
1532
            rset.close();
1533
            stmt.close();
1534
        }
1535
        catch ( SQLException e )
1536
        {
1537
            handleSQLException(e, "");
1538
        }
1539
 
7048 dpurdie 1540
        mLogger.info("queryBaselineName returned {}", retVal);
6914 dpurdie 1541
        return retVal.toString();
1542
    }
1543
 
1544
    /**only used in daemon mode
1545
     *   select config from release_manager.build_service_config where service='MAIL SERVER';
1546
     * returns the configured service 
1547
     *  
1548
     * Overridden in ReleaseManagerUtf 
1549
     *  
1550
     */
1551
    public String queryMailServer() throws SQLException, Exception
1552
    {
1553
        mLogger.debug("queryMailServer");
1554
        String retVal = "";
1555
 
1556
 
1557
        try
1558
        {
1559
            CallableStatement stmt = mConnection.prepareCall("select config from release_manager.build_service_config where service='MAIL SERVER'");
1560
            ResultSet rset = stmt.executeQuery();
1561
 
1562
            while( rset.next() )
1563
            {
1564
                String config = rset.getString("config");
1565
 
1566
                if ( config != null )
1567
                {
1568
                    retVal = config;
1569
                    break;
1570
                }
1571
            }
1572
 
1573
            rset.close();
1574
            stmt.close();
1575
        }
1576
        catch ( SQLException e )
1577
        {
1578
            handleSQLException(e, "");
1579
        }
1580
 
1581
 
7048 dpurdie 1582
        mLogger.info("queryMailServer returned {}", retVal);
6914 dpurdie 1583
        return retVal;
1584
    }
1585
 
1586
    /**only used in daemon mode
1587
     * returns the configured service 
1588
     *  
1589
     * Overridden in ReleaseManagerUtf 
1590
     *  
1591
     */
1592
    public String queryMailSender() throws SQLException, Exception
1593
    {
1594
        mLogger.debug("queryMailSender");
1595
        String retVal = "";
1596
 
1597
        try
1598
        {
1599
            CallableStatement stmt = mConnection.prepareCall("select config from release_manager.build_service_config where service='BUILD FAILURE MAIL SENDER'");
1600
            ResultSet rset = stmt.executeQuery();
1601
 
1602
            while( rset.next() )
1603
            {
1604
                String config = rset.getString("config");
1605
 
1606
                if ( config != null )
1607
                {
1608
                    retVal = config;
1609
                    break;
1610
                }
1611
            }
1612
 
1613
            rset.close();
1614
            stmt.close();
1615
        }
1616
        catch ( SQLException e )
1617
        {
1618
            handleSQLException(e, "");
1619
        }
1620
 
7048 dpurdie 1621
        mLogger.debug("queryMailSender returned {}", retVal);
6914 dpurdie 1622
        return retVal;
1623
    }
1624
 
1625
    /**only used in daemon mode
1626
     * returns the configured global email addresses 
1627
     *  
1628
     * Overridden in ReleaseManagerUtf 
1629
     */
1630
    public String queryGlobalAddresses() throws SQLException, Exception
1631
    {
1632
        mLogger.debug("queryGlobalAddresses");
1633
        String retVal = "";
1634
 
1635
        try
1636
        {
1637
            CallableStatement stmt = mConnection.prepareCall(
1638
                    "select u.user_email from release_manager.build_service_config bsc, release_manager.users u " +
1639
                            "where bsc.service='GLOBAL EMAIL ADDRESS LIST' and u.full_name=bsc.config"
1640
                    );
1641
            ResultSet rset = stmt.executeQuery();
1642
 
1643
            while( rset.next() )
1644
            {
1645
                String email = rset.getString("user_email");
1646
 
1647
                if ( email != null )
1648
                {
1649
                    retVal = email;
1650
                    break;
1651
                }
1652
            }
1653
 
1654
            rset.close();
1655
            stmt.close();
1656
        }
1657
        catch ( SQLException e )
1658
        {
1659
            handleSQLException(e, "");
1660
        }
1661
 
1662
 
7048 dpurdie 1663
        mLogger.debug("queryGlobalAddresses returned {}", retVal);
6914 dpurdie 1664
        return retVal;
1665
    }
1666
 
1667
    /**
1668
     * Determine a list of global, project wide and release email recipients
1669
     * All emails will be sent to people on this list
1670
     * @param baseline - an rtag_id
1671
     * @throws SQLException
1672
     * @returns String vector of email addresses
1673
     */
1674
    public List<String> queryProjectEmail(int baseline) throws SQLException
1675
    {
1676
        //
1677
        //  Get Global and Project Wide email information
1678
        //
1679
        mLogger.debug("queryGlobalandProjectEmail");
1680
        ArrayList<String> emailCollection = new ArrayList<String>();
1681
 
1682
        CallableStatement stmt0 = mConnection.prepareCall(
1683
                "select u.user_email " +
1684
                        "from release_manager.autobuild_failure af, " + 
1685
                        "release_manager.members_group mg, " + 
1686
                        "release_manager.users u, " + 
1687
                        "release_manager.views v, " + 
1688
                        "release_manager.release_tags rt " +
1689
                        "where rt.rtag_id=" + baseline + " " +
1690
                        "and v.view_name='PROJECT WIDE' " +
1691
                        "and af.proj_id=rt.proj_id " +
1692
                        "and af.view_id=v.view_id " +
1693
                        "and mg.group_email_id=af.group_email_id " +
1694
                        "and u.user_id=mg.user_id"
1695
                );
1696
        ResultSet rset0 = stmt0.executeQuery();
1697
        while( rset0.next() )
1698
        {
1699
            String email = rset0.getString("user_email");
1700
 
1701
            if ( email != null )
1702
            {
1703
                email = email.trim();
1704
                emailCollection.addAll( Arrays.asList(email.split("\\s*[,\\s]+\\s*")));
1705
            }
1706
        }
1707
 
1708
        rset0.close();
1709
        stmt0.close();
1710
 
1711
        //  Fetch the Release Specific email address
1712
        //  It may be comma separated
1713
        CallableStatement stmt1 = mConnection.prepareCall(
1714
                "select owner_email from release_manager.release_tags rt where rt.rtag_id = " + baseline
1715
                );
1716
        ResultSet rset1 = stmt1.executeQuery();
1717
 
1718
        while( rset1.next() )
1719
        {
1720
            String email = rset1.getString("owner_email");
1721
 
1722
            if ( email != null )
1723
            {
1724
                email = email.trim();
1725
                emailCollection.addAll( Arrays.asList(email.split("\\s*[,\\s]+\\s*")));
1726
            }
1727
        }
1728
 
1729
        rset1.close();
1730
        stmt1.close();
1731
 
1732
        return emailCollection;
1733
    }
1734
 
1735
    /**	Clears the database entry of the build file
1736
     *  <br>The assumption is that the file has been collected from the database and stored for use
1737
     *  
1738
     *  <p>sets CURRENT_BUILD_FILES to NULL for the rcon_id
1739
     */
1740
    public void clearBuildFile(int rcon_id) throws SQLException, Exception
1741
    {
1742
        mLogger.debug("clearBuildFile");
1743
 
1744
        try
1745
        {
1746
            connect();
1747
 
1748
            CallableStatement stmt = mConnection.prepareCall(
1749
                    "update release_manager.run_level" +
1750
                    " set current_build_files=NULL" +
1751
                    " where rcon_id=" + rcon_id
1752
                    );
1753
            stmt.executeUpdate();
1754
            stmt.close();
1755
            commit();
1756
        }
1757
        catch ( SQLException e )
1758
        {
1759
            handleSQLException(e, "");
1760
        }
1761
        finally
1762
        {
1763
            // this block is executed regardless of what happens in the try block
1764
            // even if an exception is thrown
1765
            // ensure disconnect
1766
            disconnect();
1767
        }
1768
    }
1769
 
1770
    /** Stores a buildfile in the database so that all daemons can collect it
1771
     * updates the CURRENT_BUILD_FILES for the rtag_id
1772
     *      This will trigger the slave build cycle
1773
     * Also sets the pkg_id and pvId of the package being built
1774
     *      This is only used for display purposes in Release manager
1775
     * 
1776
     * @param rtag_id   - Target Release
1777
     * @param buildFile - buildfile content to be saved
1778
     */
1779
    public void publishBuildFile(int rtag_id, BuildFile buildFile) throws SQLException, Exception
1780
    {
7048 dpurdie 1781
        mLogger.debug("publishBuildFile publishing a build file of length {}", buildFile.content.length());
1782
        mLogger.debug("publishBuildFile publishing pkgId: {} pvid: {}", buildFile.mPkgId, buildFile.mPvId);
6914 dpurdie 1783
 
1784
        try
1785
        {
1786
            connect();
1787
 
1788
            if ( isRtagIdConfigured( rtag_id ) )
1789
            {
1790
                PreparedStatement stmt = mConnection.prepareStatement(
1791
                        "update release_manager.run_level " +
1792
                                "    set current_build_files=?,  " +
1793
                                "        current_pkg_id_being_built=?,"+
1794
                                "        current_pv_id=?," +
1795
                                "       last_build=sysdate" +
1796
                                "    WHERE rcon_id in (  " +
1797
                                "        select rl.rcon_id from release_manager.release_config rc,  " +
1798
                                "               release_manager.run_level rl  " +
1799
                                "        where rc.rtag_id=? and rl.rcon_id=rc.rcon_id )" );
1800
                stmt.setString(1, buildFile.content);
1801
 
1802
                if (buildFile.mPkgId ==  0) {
1803
                    stmt.setNull(2, Types.NUMERIC);
1804
                } else {
1805
                    stmt.setInt  (2, buildFile.mPkgId);
1806
                }
1807
 
1808
                if (buildFile.mPvId ==  0) {
1809
                    stmt.setNull(3, Types.NUMERIC);
1810
                } else {
1811
                    stmt.setInt  (3, buildFile.mPvId);
1812
                }
1813
 
1814
                stmt.setInt(4, rtag_id);
1815
 
1816
                stmt.executeUpdate();
1817
                stmt.close();
1818
                commit();
1819
            }
1820
        }
1821
        catch ( SQLException e )
1822
        {
1823
            handleSQLException(e, "");
1824
        }
1825
        catch ( Exception e )
1826
        {
1827
            // this catch and rethrow is historical
1828
            // problems were found using CallableStatement when updating a CLOB column with data > 4000 bytes
7048 dpurdie 1829
            mLogger.error("publishBuildFile caught Exception {}", e.getMessage());
6914 dpurdie 1830
            throw new Exception("publishBuildFile caught Exception " + e.getMessage());
1831
        }
1832
        finally
1833
        {
1834
            // this block is executed regardless of what happens in the try block
1835
            // even if an exception is thrown
1836
            // ensure disconnect
1837
            disconnect();
1838
        }
1839
    }
1840
 
1841
    /**only used in daemon mode
1842
     * <br>Query the Release Sequence Number for the specified Release, while ensuing that the machine
1843
     * is still a part of the current build set
1844
     * 
1845
     * @param   rtagId      Release Identifier
1846
     * @return  <0  - No longer a part of the Build Set
1847
     * <br>     >=0 - Release Sequence Number
1848
     * 
1849
     */
1850
    public int queryReleaseSeqNum(int rtagId, int rcon_id, String machine_hostname) throws SQLException, Exception
1851
    {
1852
        mLogger.debug("queryReleaseSeqNum");
1853
        int retVal = 0;
1854
 
1855
        if ( mUseDatabase )
1856
        {
1857
            try
1858
            {
1859
                connect();
1860
                mLogger.info("queryReleaseSeqNum queryReleaseSeqNum");
1861
                CallableStatement stmt = mConnection.prepareCall(
1862
                        "SELECT NVL(rl.pause,0) AS pause, " + 
1863
                                "(select seqnum from release_modified where rtag_id = "+ rtagId +") as seqnum" +
1864
                                " FROM run_level rl," +
1865
                                "  release_config rc," +
1866
                                "  BUILD_MACHINE_CONFIG bmc" +
1867
                                " WHERE rl.rcon_id = " + rcon_id +
1868
                                " AND rl.RCON_ID   = rc.RCON_ID" +
1869
                                " AND rc.BMCON_ID IS NOT NULL" +
1870
                                " AND rc.BMCON_ID = bmc.BMCON_ID" +
1871
                                " AND rc.DAEMON_MODE = 'M'" +
1872
                                " AND UPPER(bmc.MACHINE_HOSTNAME) = UPPER('"+machine_hostname+"')"
1873
                                );
1874
 
1875
                ResultSet rset = stmt.executeQuery();
1876
                if( rset.next() )
1877
                {
1878
                    int pause = rset.getInt("pause");
1879
                    if (pause > 1)
1880
                        retVal = -2;
1881
                    else
1882
                        retVal = rset.getInt("seqnum");                        
1883
                }
1884
                else
1885
                {
1886
                    retVal = -1;
1887
                }
1888
 
1889
                rset.close();
1890
                stmt.close();
1891
            }
1892
            catch ( SQLException e )
1893
            {
1894
                handleSQLException(e, "");
1895
            }
1896
            finally
1897
            {
1898
                disconnect();
1899
            }
1900
        }
1901
 
7048 dpurdie 1902
        mLogger.warn("queryReleaseSeqNum returned {}", retVal);
6914 dpurdie 1903
        return retVal;
1904
    }
1905
 
1906
    /**
1907
     * Disable all the daemons for a specific release
1908
     *      Should only be done by the master
1909
     *      Used when master thread discovers that no build has occurred for a long time
1910
     *      
1911
     * @param rtag_id
1912
     * @throws SQLException
1913
     * @throws Exception
1914
     */
1915
    private void disableDaemons(final int rtag_id) throws SQLException, Exception
1916
    {
7048 dpurdie 1917
        mLogger.error("disableDaemons: {}", rtag_id );
6914 dpurdie 1918
 
1919
        try
1920
        {
1921
            CallableStatement stmt1 = mConnection.prepareCall( "call PK_BUILDAPI.set_daemon_states(?,2)" );
1922
            stmt1.setInt( 1, rtag_id );
1923
            stmt1.executeUpdate();
1924
            stmt1.close();
1925
            commit();
1926
        }
1927
        catch ( SQLException e )
1928
        {
1929
            handleSQLException(e, "");
1930
        }
1931
    }
1932
 
1933
    /**Checks the existence of any valid daemon configuration for the Release
1934
     * 
1935
     * A valid configuration record has a release_config entry that is linked to
1936
     * a machine_configuration entry. ie: unlinked entries are not part of a configured set.
1937
     * 
1938
     * @param   rtag_id - Release Tag to test
1939
     * @return  True if the Release still has a configuration entry
1940
     */
1941
    private boolean isRtagIdConfigured(final int rtag_id) throws SQLException, Exception
1942
    {
1943
        mLogger.debug("isRtagIdConfigured");
1944
        boolean retVal = false;
1945
 
1946
        try
1947
        {
1948
            // check if the rcon_id is still configured
1949
            CallableStatement stmt = mConnection.prepareCall(
1950
                    "select rtag_id"
1951
                    + " from release_manager.release_config"
1952
                    + " where rtag_id=" + rtag_id
1953
                    + " AND bmcon_id is not NULL");
1954
            ResultSet rset = stmt.executeQuery();
1955
 
1956
            while( rset.next() )
1957
            {
1958
                retVal = true;
1959
            }
1960
 
1961
            rset.close();
1962
            stmt.close();
1963
        }
1964
        catch ( SQLException e )
1965
        {
1966
            handleSQLException(e, "");
1967
        }
7048 dpurdie 1968
        mLogger.info("isRtagIdConfigured returning {}", retVal);
6914 dpurdie 1969
        return retVal;
1970
    }
1971
 
1972
    /**queries the RUN_LEVEL table for daemon to determine if the daemon has been paused
1973
     * or disabled.
1974
     * 
1975
     * Used as a part of allowedToProceed()
1976
     * 
1977
     * Handles the following conditions
1978
     *  Daemon has be de-configured - Returns TRUE
1979
     *  Daemon has been paused - Returns FALSE
1980
     *  Daemon has been disabled - Returns TRUE
1981
     *  Daemon has been set to run - Returns TRUE 
1982
     * 
1983
     * @param   rcon_id Connection identifier
1984
     * @returns False: Build agent has been commanded to PAUSE
1985
     *      <br>True: All other conditions
1986
     * 
1987
     * @exception SQLException
1988
     * @exception Exception
1989
     */
1990
    public boolean queryDirectedRunLevel(final int rcon_id) throws SQLException, Exception
1991
    {
7048 dpurdie 1992
        mLogger.debug("queryDirectedRunLevel {}", rcon_id);
6914 dpurdie 1993
        boolean retVal = true;
1994
 
1995
        if ( mUseDatabase )
1996
        {
1997
            try
1998
            {
1999
                CallableStatement stmt = mConnection.prepareCall(
2000
                        "select NVL(rl.pause,0) as pause" +
2001
                        " from release_manager.run_level rl, release_manager.release_config rc "+
2002
                        " where rl.rcon_id=" + rcon_id +
2003
                        " and rl.RCON_ID = rc.RCON_ID" +
2004
                        " and rc.BMCON_ID is not NULL"
2005
                        );
2006
                ResultSet rset = stmt.executeQuery();
2007
                int rsetSize = 0;
2008
 
2009
                while( rset.next() )
2010
                {
2011
                    rsetSize++;
2012
 
2013
                    //
2014
                    //  Pause: null -> 0 == Run
2015
                    //         1         == Pause
2016
                    //         2         == Disabled
2017
                    //
2018
                    int pause = rset.getInt("pause");
2019
                    if ( pause == 1) {
2020
                        retVal = false;
2021
                    }
2022
                }
2023
 
2024
                rset.close();
2025
                stmt.close();
2026
 
2027
                if ( rsetSize > 1 )
2028
                {
7033 dpurdie 2029
                    mLogger.error("queryDirectedRunLevel rsetSize > 1");
6914 dpurdie 2030
                    // show stopper
2031
                    throw new Exception("queryDirectedRunLevel rsetSize > 1");
2032
                }
2033
            }
2034
            catch ( SQLException e )
2035
            {
2036
                handleSQLException(e, "");
2037
            }
2038
        }
2039
 
7048 dpurdie 2040
        mLogger.info("queryDirectedRunLevel returning {}", retVal);
6914 dpurdie 2041
        return retVal;
2042
    }
2043
 
2044
    /**
2045
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG tables using the rcon_id primary key, rtag_id, machine_hostname, daemon_mode
2046
     * <p>Return true if the query contains a result set containing one row
2047
     *  (indicating the rcon_id is still configured and its configuration is unchanged, aside from the gbe_buildfilter)
2048
     *  the gbe_buildfilter is queried prior to usage
2049
     * 
2050
     *  <p>Used to determine if this daemon should be allowed to continue running
2051
     *  or if it should be terminated
2052
     *  
2053
     * <br>Overridden in ReleaseManagerUtf 
2054
     * 
2055
     * @param rtag_id          The rtag_id of the machine to examine
2056
     * @param rcon_id          The rcond_id of the machine to examine
2057
     * @param machine_hostname The hostname of the machine to examine
2058
     * @param daemon_mode      The daemon mode of the machine to examine
2059
     * @param threadStartTime  The time that the thread started
2060
     * 
2061
     * @return True: The machine is a part of the current build set
2062
     *         False: The machine is not a part of the current build set
2063
     * @exception SQLException
2064
     * @exception Exception
2065
     */
2066
    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
2067
    {
2068
        mLogger.debug("queryReleaseConfig 1");
2069
        boolean retVal = false;
2070
 
2071
        try
2072
        {
2073
            String sql = 
2074
                    "select rl.pause," +
2075
                    "       rt.build_age," +
2076
                    "       TRUNC((SYSDATE-rl.last_build) ) as last_build_days" +
2077
                    "   from release_manager.release_config rc," +
2078
                    "        release_manager.release_tags rt," +
2079
                    "        release_manager.run_level rl," +
2080
                    "        release_manager.build_machine_config bc" +
2081
                    "   where rc.rtag_id=?" +
2082
                    "     and rc.rcon_id=?" +
2083
                    "     and rc.bmcon_id is not NULL" +
2084
                    "     and rc.bmcon_id = bc.bmcon_id" +
2085
                    "     and bc.machine_hostname=?" +
2086
                    "     and rc.daemon_mode=?" +
2087
                    "     and rl.rcon_id=rc.rcon_id" +
2088
                    "     and rt.rtag_id=rc.rtag_id" +
2089
                    "     and (rt.official = 'N' or rt.official='R' or rt.official='C')";
2090
 
2091
            CallableStatement stmt = mConnection.prepareCall( sql );
2092
            stmt.setFetchSize(10);
2093
            stmt.setInt(1, rtag_id);
2094
            stmt.setInt(2, rcon_id);
2095
            stmt.setString(3, machine_hostname);
2096
            stmt.setString(4, Character.toString(daemon_mode));
7023 dpurdie 2097
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 1");
6914 dpurdie 2098
            int rsetSize = 0;
2099
 
2100
            while( rset.next() )
2101
            {
2102
                rsetSize++;
2103
 
2104
                //
2105
                //  Pause: null -> 0 == Run
2106
                //         1         == Pause
2107
                //         2         == Disabled
2108
                //
7023 dpurdie 2109
                int pause = rset.getInt("pause",0);
2110
                int build_age = rset.getInt("build_age", 0);
2111
                int days_since_last_build = rset.getInt("last_build_days", 0);
6914 dpurdie 2112
 
2113
                //
2114
                //  Determine if we should disable the daemons on this release because they have not been
2115
                //  used in a long while.
2116
                //
2117
                //  Only Master makes the decision
2118
                //  If build_age is zero - then the daemon does not get aged out
2119
                //  If the days since last build > build_age, then we will shut down
2120
                //      Allow one days grace - will show up IN RM for a day
2121
                //  Allow the thread to run for x hours before shutting it down
2122
                //      Handles case where daemon has just been started/restarted
2123
                //
2124
                if ( daemon_mode == 'M' &&  build_age > 0 && days_since_last_build > (build_age + 1) )
2125
                {
2126
                    long upTimeSecs = (System.currentTimeMillis() - threadStartTime)/1000;
7048 dpurdie 2127
                    mLogger.error("queryReleaseConfig 1: {},{},{},{},{},{},{}",rtag_id, rcon_id, daemon_mode, pause, build_age, days_since_last_build, upTimeSecs );
6914 dpurdie 2128
                    if ( upTimeSecs > mPostponeShutdown)
2129
                    {
2130
                        disableDaemons(rtag_id);
2131
                        pause = 2;
2132
                    }
2133
                    else
2134
                    {
7033 dpurdie 2135
                        mLogger.error("queryReleaseConfig 1: Shutdown Postponed"  );    
6914 dpurdie 2136
                    }
2137
                }
2138
 
7048 dpurdie 2139
                mLogger.info("queryReleaseConfig 1: {},{},{},{},{},{}",rtag_id, rcon_id, daemon_mode, pause, build_age, days_since_last_build  );
6914 dpurdie 2140
 
2141
                if ( pause <= 1 )
2142
                {
2143
                    retVal = true;
2144
                }
2145
            }
2146
 
2147
            rset.close();
2148
            stmt.close();
2149
 
2150
            if ( rsetSize > 1 )
2151
            {
7033 dpurdie 2152
                mLogger.error("queryReleaseConfig 1 rsetSize > 1");
6914 dpurdie 2153
                // show stopper
2154
                throw new Exception("queryReleaseConfig 1 rsetSize > 1");
2155
            }
2156
        }
2157
        catch ( SQLException e )
2158
        {
2159
            handleSQLException(e, ":1");
2160
        }
2161
 
7048 dpurdie 2162
        mLogger.info("queryReleaseConfig 1 returning {}", retVal);
6914 dpurdie 2163
        return retVal;
2164
    }
2165
 
2166
    /**removes all elements from the mReleaseConfigCollection
2167
     * handles database connection and disconnection
2168
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG tables using the rtag_id 
2169
     *  
2170
     * populates the mReleaseConfigCollection with the query result set
2171
     * partially implements the sequence diagrams coordinate slave threads generate build files 
2172
     *  
2173
     * Used by Master Thread to determine the build machines that will be a part 
2174
     * of the Slave-Sync process.
2175
     * 
2176
     *  Only called when a database connection has been established
2177
     */
2178
    public void queryReleaseConfig(final int rtag_id) throws SQLException, Exception
2179
    {
2180
        mLogger.debug("queryReleaseConfig 2");
2181
        mReleaseConfigCollection.resetData();
2182
 
2183
        try
2184
        {
2185
            //connect();
2186
 
2187
            CallableStatement stmt = mConnection.prepareCall(
2188
                    " select rc.rcon_id,"+
2189
                    "        rc.daemon_mode,"+
2190
                    "        rl.pause,"+
2191
                    "        bc.machine_hostname,"+
2192
                    "        rc.gbe_buildfilter,"+
2193
                    "        mt.gbe_value,"+
2194
                    "        bm.bm_name" +
2195
                    "    from release_manager.release_config rc, " +
2196
                    "         release_manager.run_level rl, " +
2197
                    "         release_manager.build_machine_config bc, " +
2198
                    "         release_manager.gbe_machtype mt," +
2199
                    "         release_manager.build_machines bm" +
2200
                    "    where   rc.rtag_id=?" +
2201
                    "        and rl.rcon_id=rc.rcon_id " +
2202
                    "        and rc.bmcon_id is not NULL" +
2203
                    "        and rc.bmcon_id = bc.bmcon_id" +
2204
                    "        and mt.gbe_id=bc.gbe_id" +
2205
                    "        and mt.bm_id=bm.bm_id"
2206
                    );
2207
            stmt.setFetchSize(10);
2208
            stmt.setInt(1, rtag_id);
7023 dpurdie 2209
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 2");
6914 dpurdie 2210
 
2211
            while( rset.next() )
2212
            {
7023 dpurdie 2213
                int rcon_id = rset.mustGetInt("rcon_id");
2214
 
6914 dpurdie 2215
                char dm = 'S';          
7023 dpurdie 2216
                String daemon_mode = rset.getString("daemon_mode","S");
2217
 
7048 dpurdie 2218
                mLogger.info("queryReleaseConfig 2 daemon_mode '{}'", daemon_mode);
6914 dpurdie 2219
 
7023 dpurdie 2220
                if ( daemon_mode.compareTo("M") == 0 )
6914 dpurdie 2221
                {
7023 dpurdie 2222
                    dm = 'M';
6914 dpurdie 2223
                }
2224
 
7023 dpurdie 2225
                String machine_hostname = rset.mustGetString("machine_hostname");
2226
                String gbe_buildfilter = rset.getString("gbe_buildfilter","");
2227
                String gbe_machtype = rset.mustGetString("gbe_value");
2228
                String gbe_machclass = rset.mustGetString("bm_name");
6914 dpurdie 2229
                //
2230
                //  Pause: null -> 0 == Run
2231
                //         1         == Pause
2232
                //         2         == Disabled
2233
                //
7023 dpurdie 2234
                int pause = rset.getInt("pause",0);
6914 dpurdie 2235
                mLogger.info("queryReleaseConfig 2: " + rtag_id + ", " + rcon_id + ", "+ dm + ", " + pause + 
2236
                        ", " + machine_hostname + ", " + gbe_buildfilter + ", " + gbe_machtype + ", + " + gbe_machclass );
2237
 
2238
                //
2239
                // Daemon Mode : Do not include build daemons that are disabled
2240
                // Escrow Mode : Include all machines
2241
                //
2242
                if ( pause <= 1 ||  ! mDaemon )
2243
                {
2244
                    ReleaseConfig releaseConfig = new ReleaseConfig( rtag_id, rcon_id, dm, machine_hostname, gbe_buildfilter, gbe_machtype, gbe_machclass);
2245
                    mReleaseConfigCollection.add(releaseConfig);
2246
                }
2247
            }
2248
 
2249
 
2250
            rset.close();
2251
            stmt.close();
2252
        }
2253
        catch ( SQLException e )
2254
        {
2255
            handleSQLException(e, ":2");
2256
        }
2257
        finally
2258
        {
2259
            // this block is executed regardless of what happens in the try block
2260
            // even if an exception is thrown
2261
            // ensure disconnect
2262
            //disconnect();
2263
        }
2264
    }
2265
 
2266
    /**removes all elements from the mReleaseConfigCollection
2267
     * handles database connection and disconnection
2268
     * queries the RELEASE_CONFIG and BUILD_MACHINE_CONFIG table using the machine_hostname
2269
     * populates the mReleaseConfigCollection with the query result set
2270
     * partially implements the sequence diagram spawn thread 
2271
     *  
2272
     * Used by the BuildDaemon thread to determine daemons to start and stop
2273
     */
2274
    public void queryReleaseConfig(final String hostname) throws SQLException, Exception
2275
    {
7048 dpurdie 2276
        mLogger.debug("queryReleaseConfig 3 {}", hostname);
6914 dpurdie 2277
        mReleaseConfigCollection.resetData();
2278
 
2279
        try
2280
        {
2281
            connect();
2282
            CallableStatement stmt = mConnection.prepareCall(
2283
                    "select rc.rtag_id,"+
2284
                    "       rc.rcon_id,"+
2285
                    "       rc.daemon_mode,"+
2286
                    "       rl.pause,"+
2287
                    "       bc.machine_hostname,"+
2288
                    "       rc.gbe_buildfilter,"+
2289
                    "       mt.gbe_value,"+
2290
                    "       bm.bm_name" +
2291
                    "  from release_manager.release_config rc," +
2292
                    "       release_manager.release_tags rt," +
2293
                    "       release_manager.run_level rl," +
2294
                    "       release_manager.build_machine_config bc," +
2295
                    "       release_manager.gbe_machtype mt," +
2296
                    "       release_manager.build_machines bm " +
2297
                    "    where bc.machine_hostname=?" +
2298
                    "      and rt.rtag_id=rc.rtag_id" +
2299
                    "      and rl.rcon_id=rc.rcon_id" +
2300
                    "      and rc.bmcon_id is not NULL" +
2301
                    "      and bc.bmcon_id=rc.bmcon_id" +
2302
                    "      and mt.gbe_id=bc.gbe_id" +
2303
                    "      and mt.bm_id=bm.bm_id" +
2304
                    "      and (rt.official = 'N' or rt.official='R' or rt.official='C')"
2305
                    );
2306
 
2307
            stmt.setFetchSize(20);
2308
            stmt.setString(1, hostname);
7023 dpurdie 2309
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryReleaseConfig 3");
6914 dpurdie 2310
 
2311
            while( rset.next() )
2312
            {
7023 dpurdie 2313
                int rtag_id = rset.mustGetKeyInt("rtag_id");
2314
                int rcon_id = rset.mustGetInt("rcon_id");
6914 dpurdie 2315
 
2316
                char dm = 'S';          
7023 dpurdie 2317
                String daemon_mode = rset.getString("daemon_mode", "S");
6914 dpurdie 2318
 
7048 dpurdie 2319
                mLogger.info("queryReleaseConfig 3 daemon_mode '{}'", daemon_mode);
6914 dpurdie 2320
 
7023 dpurdie 2321
                if ( daemon_mode.compareTo("M") == 0 )
6914 dpurdie 2322
                {
7023 dpurdie 2323
                    dm = 'M';
6914 dpurdie 2324
                }
2325
 
7023 dpurdie 2326
                String machine_hostname = rset.mustGetString("machine_hostname");
2327
                String gbe_buildfilter = rset.getString("gbe_buildfilter",null);
2328
                String gbe_machtype = rset.mustGetString("gbe_value");
2329
                String gbe_machclass = rset.mustGetString("bm_name");
2330
 
6914 dpurdie 2331
                //
2332
                //  Pause: null -> 0 == Run
2333
                //         1         == Pause
2334
                //         2         == Disabled
2335
                //
7023 dpurdie 2336
                int pause = rset.getInt("pause",0);
2337
 
6914 dpurdie 2338
                mLogger.info("queryReleaseConfig 3: " + rtag_id + ", " + rcon_id + ", "+ dm + ", " + pause + 
2339
                        ", " + machine_hostname + ", " + gbe_buildfilter + ", " + gbe_machtype + ", + " + gbe_machclass );
2340
 
2341
                //
2342
                // Do not include build daemons that are disabled
2343
                // Only those that are running or paused
2344
                //
2345
                if ( pause <= 1 )
2346
                {
2347
                    ReleaseConfig releaseConfig = new ReleaseConfig( rtag_id, rcon_id, dm, machine_hostname, gbe_buildfilter, gbe_machtype, gbe_machclass);
2348
                    mReleaseConfigCollection.add(releaseConfig);
2349
                }
2350
            }
2351
 
2352
            rset.close();
2353
            stmt.close();
2354
        }
2355
        catch ( SQLException e )
2356
        {
2357
            handleSQLException(e, ":3");
2358
        }
2359
        finally
2360
        {
2361
            // this block is executed regardless of what happens in the try block
2362
            // even if an exception is thrown
2363
            // ensure disconnect
2364
            disconnect();
2365
        }
2366
 
2367
    }
2368
 
2369
    /** Check that the build set has exactly one master
2370
     *  
2371
     *  Ignores entries that are disabled
2372
     *  Ignore entries that have been 'unlinked' - they have no active machine configuration
2373
     *
2374
     *   @param rtag_id - Release Tag
2375
     *  
2376
     *  Used by the Master and Slave Daemons 
2377
     *  Overridden in ReleaseManagerUtf 
2378
     */
2379
    public int queryMasterCount(final int rtag_id) throws SQLException, Exception
2380
    {
7048 dpurdie 2381
        mLogger.debug("queryMasterCount rtag_id {}", rtag_id);
6914 dpurdie 2382
 
2383
        int masterCount = 0;
2384
        try
2385
        {
2386
            connect();
2387
            CallableStatement stmt = mConnection.prepareCall(
2388
                            "SELECT COUNT (rc.daemon_mode) as masterCount" +
2389
                            " FROM release_manager.release_config rc, release_manager.run_level rl" +
2390
                            " WHERE rc.rtag_id =" + rtag_id +
2391
                            " AND rl.RCON_ID = rc.RCON_ID" +
2392
                            " AND   rc.bmcon_id is not NULL" +
2393
                            " AND NVL(rl.PAUSE,0) != 2" +
2394
                            " GROUP BY rc.daemon_mode" +
2395
                            " HAVING rc.daemon_mode = 'M'" );
2396
 
2397
            ResultSet rset = stmt.executeQuery();
2398
 
2399
            if ( rset.next() )
2400
            {
2401
                masterCount = rset.getInt("masterCount");
2402
            }
2403
 
2404
            rset.close();
2405
            stmt.close();
2406
        }
2407
        catch ( SQLException e )
2408
        {
2409
            handleSQLException(e, "");
2410
        }
2411
        finally
2412
        {
2413
            // this block is executed regardless of what happens in the try block
2414
            // even if an exception is thrown
2415
            // ensure disconnect
2416
            disconnect();
2417
        }
2418
 
2419
        return masterCount;
2420
    }
2421
 
2422
    /**
2423
     * Determine an array of machines for which there are active build requests
2424
     * Used to notify slave machines of a pending build request
2425
     * 
2426
     *  
2427
     * @param mHostname - Identifies the build machine
2428
     * @param rconIdList - Comma separated list of RCON_IDs that we are interested in
2429
     * @return An array of Integers, each being the rcon_id of a machine that has an active build
2430
     * @throws Exception 
2431
     */
2432
    public ArrayList<Integer> queryActivatedBuilds(String mHostname, String rconIdList) throws Exception {
2433
 
2434
        ArrayList<Integer> rv = new ArrayList<Integer>();
2435
        try
2436
        {
2437
            connect();
2438
            PreparedStatement stmt = mConnection.prepareStatement(
2439
                    "SELECT rl.rcon_id, rc.RTAG_ID" +
2440
                    " FROM run_level rl, release_config rc, release_tags rt" +
2441
                    " WHERE  rt.rtag_id = rc.RTAG_ID" +
2442
                    " AND UPPER(rc.daemon_hostname) = UPPER('"+mHostname+"')" +
2443
                    " AND rc.DAEMON_MODE != 'M'" +
2444
                    " AND rc.RCON_ID = rl.rcon_id" +
2445
                    " AND CURRENT_BUILD_FILES IS NOT NULL" +
2446
                    " AND rl.pause is null" +
2447
                    " AND rl.rcon_id in ("+rconIdList+")"
2448
                    );
2449
 
2450
            ResultSet rset = stmt.executeQuery();
2451
 
2452
            while (rset.next()) {
2453
                Integer ii = rset.getInt("rcon_id");
2454
                rv.add(ii);
2455
            }
2456
 
2457
            rset.close();
2458
            stmt.close();
2459
        }
2460
        catch ( SQLException e )
2461
        {
2462
            handleSQLException(e, "");
2463
        }
2464
        finally
2465
        {
2466
            // this block is executed regardless of what happens in the try block
2467
            // even if an exception is thrown
2468
            // ensure disconnect
2469
            disconnect();
2470
        }
2471
        return rv;
2472
    }
2473
 
7048 dpurdie 2474
    /**
2475
     * Extract all package-version information for released packages
2476
     * Used in both Escrow and non-Escrow modes
2477
     * 
2478
     * @param   rippleEngine        - Instance to use
2479
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2480
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
6914 dpurdie 2481
     *  
2482
     * Overridden in ReleaseManagerUtf
2483
     *  
2484
     */
7048 dpurdie 2485
    protected void queryPackageVersions(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
6914 dpurdie 2486
    {
2487
        Phase phase = new Phase("rmData");
7048 dpurdie 2488
        mLogger.debug("queryPackageVersions {}", mDaemon);
6914 dpurdie 2489
 
2490
        try
2491
        {
2492
            if (mDaemon)
2493
            {
7048 dpurdie 2494
                // Get package information on ALL released packages within the release of interest
6914 dpurdie 2495
                //
2496
                mLogger.debug("queryPackageVersions: stmt8");
2497
                phase.setPhase("getAllPkgs1");
2498
                PreparedStatement stmt8 = mConnection.prepareStatement(
2499
                        "SELECT rc.pv_id," +
7048 dpurdie 2500
                                " p.pkg_id," +
2501
                                " p.pkg_name," +
2502
                                " pv.pkg_version," +
2503
                                " pv.v_ext," +
2504
                                " pv.ripple_field," +
2505
                                " pv.major_limit," +
2506
                                " pv.minor_limit," +
2507
                                " pv.patch_limit," +
2508
                                " pv.build_number_limit," +
2509
                                " pv.build_type," +
2510
                                " rc.sdktag_id," +
2511
                                " rc.ripple_stop," +
2512
                                " peg.pv_id as pegged," +
2513
                                " release_manager.PK_RMAPI.return_vcs_tag(rc.pv_id) AS vcsTag," +
2514
                                " pv.build_time" +
6914 dpurdie 2515
                                " FROM release_manager.release_content rc," +
2516
                                "  release_manager.package_versions pv," +
2517
                                "  release_manager.packages p," +
2518
                                "  release_manager.pegged_versions peg" +
2519
                                " WHERE rc.rtag_id= " + baseline +
2520
                                " AND pv.pv_id    = rc.pv_id" +
2521
                                " AND p.pkg_id    = pv.pkg_id" +
2522
                                " AND peg.rtag_id(+) = rc.rtag_id" +
2523
                                " AND peg.pv_id(+) = rc.pv_id" +
2524
                                " ORDER BY rc.pv_id"
2525
                        );
2526
                mLogger.debug("queryPackageVersions: stmt8 Prepared");
2527
                stmt8.setFetchSize(1000);
7023 dpurdie 2528
                RmResultSet rset8 = new RmResultSet(stmt8.executeQuery(), "queryPackageVersions rset8");
6914 dpurdie 2529
                mLogger.debug("queryPackageVersions: stmt8 Query Done");
2530
 
2531
                while( rset8.next() )
2532
                {
7023 dpurdie 2533
                    int pv_id = rset8.mustGetKeyInt("pv_id");
2534
                    int pkg_id = rset8.mustGetInt("pkg_id");
2535
                    String pkg_name = rset8.mustGetString("pkg_name");
2536
                    String pkg_version = rset8.mustGetString("pkg_version");
2537
                    String v_ext = rset8.getString("v_ext", "");
2538
                    String ripple_field = rset8.getString("ripple_field", "b");
2539
                    int major_limit = rset8.getInt("major_limit",0);
2540
                    int minor_limit = rset8.getInt("minor_limit", 0);
2541
                    int patch_limit = rset8.getInt("patch_limit",0);
2542
                    int build_number_limit = rset8.getInt("build_number_limit", 0);
2543
                    String vcs_tag = rset8.getString("vcsTag","");
2544
                    int isAnSdk = rset8.getInt("sdktag_id",0); 
2545
                    int isPegged = rset8.getInt("pegged",0);
2546
                    String buildType = rset8.getString("build_type", null);
6914 dpurdie 2547
                    boolean isBuildable = ( buildType != null ) && (buildType.equals("A") || buildType.equals("Y") );
7048 dpurdie 2548
                    int buildTime = rset8.getInt("build_time", 60);
6914 dpurdie 2549
 
7023 dpurdie 2550
                    String rippleStopData = rset8.getString("ripple_stop","n");
2551
                    char rippleStop = rippleStopData.charAt(0);
6914 dpurdie 2552
 
2553
                    Package p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
2554
                    p.mMajorLimit = major_limit;
2555
                    p.mMinorLimit = minor_limit;
2556
                    p.mPatchLimit = patch_limit;
2557
                    p.mBuildLimit = build_number_limit;
2558
                    p.mIsSdk = isAnSdk > 0;
2559
                    p.mIsPegged = isPegged > 0;
2560
                    p.mIsBuildable = isBuildable;
2561
                    p.mRippleStop = rippleStop;
7048 dpurdie 2562
                    p.mBuildTime = buildTime;
6914 dpurdie 2563
 
2564
                    //  If this package is to be replaced by a planned package then
2565
                    //  insert some of the current packages attributes
2566
                    //  Otherwise, add the the package to the package collection
2567
                    //
7078 dpurdie 2568
 
6914 dpurdie 2569
                    Package plannedPackage = findPackage(p.mAlias, packageCollection);
2570
                    if ( plannedPackage == NULL_PACKAGE )
2571
                    {
7048 dpurdie 2572
                        mLogger.info("queryPackageVersions rset8 no planned package {}", pv_id);
6914 dpurdie 2573
                        packageCollection.add(p);
2574
                    }
2575
                    else
2576
                    {
2577
                        //  Copy these flags from the package that will be replaced
2578
                        //      Should not be able to replace a package provided by an SDK
2579
                        plannedPackage.mIsSdk = p.mIsSdk;
2580
 
2581
                        // A pegged package can be replaced with a directly built package
2582
                        // plannedPackage.mIsPegged = p.mIsPegged;
2583
                    }
2584
                }
2585
 
2586
                mLogger.debug("queryPackageVersions: stmt8 processing complete");
2587
                rset8.close();
2588
                stmt8.close();
2589
 
2590
                // get released package dependency info
2591
                // 
2592
                mLogger.debug("queryPackageVersions: stmt9");
2593
                phase.setPhase("getAllPkgs2");
2594
                PreparedStatement stmt9 = mConnection.prepareStatement(
7023 dpurdie 2595
                        "select rc.pv_id as pv_id, dpv.pv_id as dpv_id, p.pkg_name, dpv.v_ext" +
6914 dpurdie 2596
                                " from release_manager.release_content rc," +
2597
                                "      release_manager.package_versions pv," + 
2598
                                "      release_manager.package_dependencies pd,"+
2599
                                "      release_manager.package_versions dpv,"+
2600
                                "      release_manager.packages p" +
2601
                                " where rc.rtag_id=" + baseline +
2602
                                "  and pv.pv_id = rc.pv_id" +
2603
                                "  and pd.pv_id=pv.pv_id" +
2604
                                "  and dpv.pv_id=pd.dpv_id" +
2605
                                "  and p.pkg_id=dpv.pkg_id" +
2606
                                " order by rc.pv_id"
2607
                        );
2608
                mLogger.debug("queryPackageVersions: stmt9 prepared");
2609
                stmt9.setFetchSize(1000);
7023 dpurdie 2610
                RmResultSet rset9 = new RmResultSet(stmt9.executeQuery(), "queryPackageVersions rset9");
6914 dpurdie 2611
                mLogger.debug("queryPackageVersions: stmt9 query done");
2612
 
2613
                while( rset9.next() )
2614
                {
7023 dpurdie 2615
                    int pv_id = rset9.mustGetKeyInt("pv_id");
2616
                    int dpv_id = rset9.mustGetInt("dpv_id");
2617
                    String pkg_name = rset9.mustGetString("pkg_name");
2618
                    String v_ext = rset9.getString("v_ext","");
6914 dpurdie 2619
 
7048 dpurdie 2620
                    Package p = findPackage(pv_id, packageCollection);
2621
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2622
                    {
2623
                        p.mDependencyCollection.add(pkg_name + v_ext);
2624
                        p.mDependencyIDCollection.add(dpv_id);
2625
                    }
7048 dpurdie 2626
 
6914 dpurdie 2627
                }
2628
                mLogger.debug("queryPackageVersions: stmt9 processing complete");
2629
 
2630
                rset9.close();
2631
                stmt9.close();
2632
 
2633
                // get released package build info
2634
                mLogger.debug("queryPackageVersions: stmt10");
2635
                phase.setPhase("getAllPkgs3");
2636
                PreparedStatement stmt10 = mConnection.prepareStatement(
2637
                        "select rc.pv_id, bm.bm_name, bsa.bsa_name " +
2638
                                "from release_manager.release_content rc," +
2639
                                "     release_manager.package_versions pv," +
2640
                                "     release_manager.package_build_info pbi," +
2641
                                "     release_manager.build_machines bm," +
2642
                                "     release_manager.build_standards_addendum bsa " +
2643
                                "where rc.rtag_id=?" + 
2644
                                "     and pv.pv_id = rc.pv_id" +
2645
                                "     and pbi.pv_id=pv.pv_id" +
2646
                                "     and bm.bm_id=pbi.bm_id" +
2647
                                "     and bsa.bsa_id=pbi.bsa_id " +
2648
                                "order by rc.pv_id"
2649
                        );
2650
                stmt10.setFetchSize(1000);
2651
                stmt10.setInt(1, baseline);
7023 dpurdie 2652
                RmResultSet rset10 = new RmResultSet(stmt10.executeQuery(), "queryPackageVersions rset10");
6914 dpurdie 2653
 
2654
                while( rset10.next() )
2655
                {
7023 dpurdie 2656
                    int pv_id = rset10.mustGetKeyInt("pv_id");
2657
                    String bm_name = rset10.mustGetString("bm_name");
2658
                    String bsa_name = rset10.mustGetString("bsa_name");
6914 dpurdie 2659
 
7048 dpurdie 2660
                    Package p = findPackage(pv_id, packageCollection);
2661
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2662
                    {
2663
                        BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
2664
                        if ( bs.supportedBuildStandard() )
2665
                        {
2666
                            p.mBuildStandardCollection.add(bs);
2667
                        }
2668
                    }
2669
                }
2670
 
2671
                rset10.close();
2672
                stmt10.close();
2673
 
2674
                // get released package unit test info
2675
                mLogger.debug("queryPackageVersions: stmt11");
2676
                phase.setPhase("getAllPkgs4");
2677
                PreparedStatement stmt11 = mConnection.prepareStatement(
2678
                        "select rc.pv_id, tt.test_type_name " +
2679
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.unit_tests ut, release_manager.test_types tt " +
2680
                                "where rc.rtag_id=" + baseline +
2681
                                " and pv.pv_id = rc.pv_id and ut.pv_id=pv.pv_id and tt.test_type_id=ut.test_types_fk " +
2682
                                "order by rc.pv_id"
2683
                        );
2684
                stmt11.setFetchSize(1000);
7023 dpurdie 2685
                RmResultSet rset11 = new RmResultSet(stmt11.executeQuery(), "queryPackageVersions rset11");
6914 dpurdie 2686
 
2687
                while( rset11.next() )
2688
                {
7023 dpurdie 2689
                    int pv_id = rset11.mustGetKeyInt("pv_id");
7048 dpurdie 2690
                    String test_type_name = rset11.mustGetString("test_type_name");
6914 dpurdie 2691
                    Package p = findPackage(pv_id, packageCollection);
7048 dpurdie 2692
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2693
                    {
2694
                        if ( test_type_name.compareTo("Autobuild UTF") == 0 )
2695
                        {
2696
                            p.mHasAutomatedUnitTests = true;
2697
                        }
2698
                    }
2699
                }
2700
 
2701
                rset11.close();
2702
                stmt11.close();
2703
 
2704
                // get released package build failure info...
2705
                // view based
2706
                mLogger.debug("queryPackageVersions: stmt12");
2707
                phase.setPhase("getAllPkgs5");
2708
                PreparedStatement stmt12 = mConnection.prepareStatement(
2709
                        "SELECT rc.pv_id," +
2710
                        "  u.user_email" +
2711
                        " FROM release_manager.release_content rc," +
2712
                        "  release_manager.release_tags rt," +
2713
                        "  release_manager.package_versions pv," +
2714
                        "  release_manager.autobuild_failure af," +
2715
                        "  release_manager.members_group mg," +
2716
                        "  release_manager.users u" +
2717
                        " WHERE rc.rtag_id     = " + baseline +
2718
                        " AND rt.rtag_id       = rc.rtag_id" +
2719
                        " AND pv.pv_id         = rc.pv_id" +
2720
                        " AND af.view_id       = rc.base_view_id" +
2721
                        " AND mg.group_email_id= af.group_email_id" +
2722
                        " AND u.user_id        = mg.user_id" +
2723
                        " AND af.proj_id       = rt.proj_id" +
2724
                        " ORDER BY rc.pv_id"
2725
                        );
2726
                stmt12.setFetchSize(1000);
7023 dpurdie 2727
                RmResultSet rset12 = new RmResultSet(stmt12.executeQuery(), "queryPackageVersions rset12");
6914 dpurdie 2728
 
2729
                while( rset12.next() )
2730
                {
7023 dpurdie 2731
                    int pv_id = rset12.mustGetKeyInt("pv_id");
7048 dpurdie 2732
                    String user_email = rset12.getString("user_email",null);
6914 dpurdie 2733
                    Package p = findPackage(pv_id, packageCollection);
2734
 
7048 dpurdie 2735
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2736
                    {
7048 dpurdie 2737
                        p.addEmail(user_email);
6914 dpurdie 2738
                    }
2739
                }
2740
 
2741
                rset12.close();
2742
                stmt12.close();
2743
 
2744
                // get released advisory ripple info
2745
                mLogger.debug("queryPackageVersions: stmt14");
2746
                phase.setPhase("getAllPkgs6");
2747
                PreparedStatement stmt14 = mConnection.prepareStatement(
2748
                        "select rc.pv_id " +
2749
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.advisory_ripple ar " +
2750
                                "where rc.rtag_id=" + baseline +
2751
                                " and pv.pv_id = rc.pv_id and ar.rtag_id=rc.rtag_id and ar.pv_id=rc.pv_id " +
2752
                                "order by rc.pv_id"
2753
                        );
2754
                stmt14.setFetchSize(1000);
7023 dpurdie 2755
                RmResultSet rset14 = new RmResultSet(stmt14.executeQuery(), "queryPackageVersions rset14");
6914 dpurdie 2756
 
2757
                while( rset14.next() )
2758
                {
7023 dpurdie 2759
                    int pv_id = rset14.mustGetInt("pv_id");
6914 dpurdie 2760
                    Package p = findPackage(pv_id, packageCollection);
7048 dpurdie 2761
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2762
                    {
2763
                        p.mAdvisoryRipple = true;
2764
                    }
2765
                }
2766
 
2767
                rset14.close();
2768
                stmt14.close();
7023 dpurdie 2769
 
6914 dpurdie 2770
            }
2771
            else
2772
            {
2773
                // Escrow Mode
2774
                // get released product info
2775
                mLogger.debug("queryPackageVersions: stmt18");
2776
                PreparedStatement stmt = mConnection.prepareStatement(
2777
                        "select oc.prod_id, p.pkg_name, pv.pkg_version, pv.v_ext," +
2778
                                "release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag" +
2779
                                " from deployment_manager.bom_contents bc," +
2780
                                "deployment_manager.operating_systems os," +
2781
                                "deployment_manager.os_contents oc," +
2782
                                "release_manager.package_versions pv," +
2783
                                "release_manager.packages p" +
2784
                                " where bc.bom_id=" + baseline +
2785
                                " and os.node_id=bc.node_id" +
2786
                                " and oc.os_id=os.os_id" +
2787
                                " and pv.pv_id=oc.prod_id" +
2788
                                " and p.pkg_id=pv.pkg_id" +
2789
                                " order by oc.prod_id"
2790
                        );
2791
                stmt.setFetchSize(1000);
7023 dpurdie 2792
                RmResultSet rset = new RmResultSet(stmt.executeQuery(), "queryPackageVersions rset");
6914 dpurdie 2793
 
2794
                while( rset.next() )
2795
                {
7023 dpurdie 2796
                    int pv_id = rset.mustGetKeyInt("prod_id");
2797
                    String pkg_name = rset.mustGetString("pkg_name");
2798
                    String pkg_version = rset.mustGetString("pkg_version");
2799
                    String v_ext = rset.getString("v_ext", "");
2800
                    String vcs_tag = rset.getString("vcsTag","");
2801
 
6914 dpurdie 2802
                    Package p = findPackage(pv_id, packageCollection);
2803
                    if ( p == NULL_PACKAGE )
2804
                    {
2805
                        Package q = new Package(0, pv_id, pkg_name, pkg_version, v_ext, pkg_name + "." + pkg_version, vcs_tag, 'x');
2806
                        packageCollection.add(q);
2807
                    }
2808
                }
2809
 
2810
                rset.close();
2811
                stmt.close();
7048 dpurdie 2812
 
2813
                //  Now have all the package-versions used in the SBOM need to 
2814
                //      determine all the dependent packages 
2815
                //      determine the build info for all the packages
2816
 
2817
                //  Determine all dependent packages
2818
                //  Note: use a ListIterator as it allows traverseDependencies to modify the packageCollection
2819
                for (ListIterator<Package> it = packageCollection.listIterator(); it.hasNext(); )
2820
                {
2821
                    Package p = it.next();
2822
                    traverseDependencies(packageCollection, p, false, it);
2823
                }
2824
 
2825
                //  Add required build information
2826
                for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
2827
                {
2828
                    Package p = it.next();
2829
                    queryBuildInfo(rippleEngine, p);
2830
                }
6914 dpurdie 2831
            }
2832
        }
2833
        catch ( SQLException e )
2834
        {
2835
            handleSQLException(e, "");
2836
        }
7048 dpurdie 2837
        phase.setPhase("End");
2838
    }
2839
 
2840
    /**
2841
     * Extract all package-version information for Planned Packages (WIPS)
2842
     * Not used in ESCROW
2843
     * 
2844
     * @param   rippleEngine        - Instance to use
2845
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2846
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
2847
     *  
2848
     * Overridden in ReleaseManagerUtf
2849
     *  
2850
     */
2851
    protected void queryWips(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
2852
    {
2853
        if (!mDaemon){
2854
            return;
2855
        }
2856
 
2857
        Phase phase = new Phase("rmData");
2858
        mLogger.debug("queryWips {}", mDaemon);
6914 dpurdie 2859
 
7048 dpurdie 2860
        try
6914 dpurdie 2861
        {
7048 dpurdie 2862
            // Get planned package info
2863
            // Support multiple WIPS on the same package and build in the order they were released
2864
            // These are packages that are marked as pending build
2865
            //
2866
            mLogger.debug("queryPackageVersions: stmt1");
2867
            phase.setPhase("getPlannedPkgs1");
2868
            PreparedStatement stmt1 = mConnection.prepareStatement(
7080 dpurdie 2869
                    "select pl.pv_id, pv.modified_stamp" +
7048 dpurdie 2870
                            " from release_manager.planned pl," +
2871
                            "      release_manager.package_versions pv," +
2872
                            "      release_manager.packages p" +
2873
                            " where pl.rtag_id=" + baseline +
2874
                            "   and pv.build_type='A' and pv.dlocked='A'" +
2875
                            "   and pv.pv_id=pl.pv_id and p.pkg_id=pv.pkg_id" +
2876
                            " order by pv.modified_stamp"
2877
                    );
2878
            stmt1.setFetchSize(500);
2879
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "queryPackageVersions rset1");
2880
 
2881
            while( rset1.next() )
6914 dpurdie 2882
            {
7048 dpurdie 2883
                int pvId = rset1.mustGetKeyInt("pv_id");
2884
 
7093 dpurdie 2885
                Package p = getPackageInfo(pvId, rippleEngine, true);
7048 dpurdie 2886
                if ( p != NULL_PACKAGE)
2887
                {
2888
                    p.mIsNotReleased = true;
2889
                    p.mDirectlyPlanned = true;
2890
                    p.mBuildReason = BuildReason.NewVersion;
2891
 
2892
                    // If there are multiple packages with the same Alias, then only the first one
2893
                    // will be placed in the build set. The will be the oldest, the first one released
2894
                    // to be built
2895
 
2896
                    Package prevPlannedPackage = findPackage(p.mAlias, packageCollection);
2897
                    if ( prevPlannedPackage == NULL_PACKAGE )
2898
                    {
2899
                        mLogger.info("queryWips rset1 no previous WIP package {}", pvId);
2900
                        packageCollection.add(p);
2901
                    }
2902
                }
6914 dpurdie 2903
            }
2904
 
7048 dpurdie 2905
            rset1.close();
2906
            stmt1.close();
2907
 
2908
            //  Process Scheduled Build Approvals. OpCode is 2
2909
            //      These are treated as requests to not-include a 'Pending' package-version in the current build set
2910
            //      If there is an un-expired instruction, then remove the pending package-version from the build set
2911
            //
2912
            //  Process all expired requests
2913
            //      These are scheduled builds were the scheduled time has been exceeded
2914
            //      Simply discard the instruction and let the Approved build proceed
2915
            //
2916
            DaemonInstruction di = new DaemonInstruction(baseline, 2, true);
2917
 
2918
            phase.setPhase("removeOldSchedBuilds");
2919
            while ( getDaemonInst( di ) )
6914 dpurdie 2920
            {
7048 dpurdie 2921
                markDaemonInstCompleted(di.instruction);
2922
                mLogger.info("queryPackageVersions remove Scheduled Build Approvals {}", di.pvId);
6914 dpurdie 2923
            }
7048 dpurdie 2924
 
2925
            phase.setPhase("getSchedBuilds");
2926
            di = new DaemonInstruction(baseline, 2, false);
2927
            while ( getDaemonInst( di ) )
2928
            {
2929
                Package p = findPackage(di.pvId, packageCollection);
2930
 
2931
                if ( p != NULL_PACKAGE )
2932
                {
2933
                    mLogger.info("queryPackageVersions Scheduled Build Approvals {}", di.pvId);
2934
                    packageCollection.remove(p);
2935
                }
2936
                else
2937
                {
2938
                    // discard - the package no longer exists
2939
                    markDaemonInstCompleted( di.instruction );
2940
                    mLogger.info("queryPackageVersions remove Scheduled Build Approvals for nonexistent package {}", di.pvId);
2941
                }
2942
            }                
2943
 
6914 dpurdie 2944
        }
7048 dpurdie 2945
        catch ( SQLException e )
2946
        {
2947
            handleSQLException(e, "");
2948
        }
6914 dpurdie 2949
        phase.setPhase("End");
2950
    }
2951
 
7048 dpurdie 2952
    /**
2953
     * Extract all TEST package-version information
2954
     * Only active in Daemon Mode
2955
     * 
2956
     * @param   rippleEngine        - Instance to use
2957
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2958
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
2959
     *  
2960
     * Overridden in ReleaseManagerUtf
2961
     *  
2962
     */
2963
    protected void queryTest(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
2964
    {
2965
        if (!mDaemon){
2966
            return;
2967
        }
2968
 
2969
        Phase phase = new Phase("rmData");
2970
        mLogger.debug("queryTest {}", mDaemon);
2971
 
2972
        try
2973
        {
2974
 
2975
            // Daemon Instruction: Test Build Package
2976
            //  An op code of 1 means test build
2977
            //
2978
            // Trust nothing - these are mostly wips that at any time may have:
2979
            // - no build location
2980
            // - no build label
2981
            // - an empty build standard collection
2982
            // proceed with defaults above if necessary (the build will subsequently fail)
2983
            // in all cases, build a meaningful email body to inform the user
2984
            // of the snapshot of build information that applied to the build and store in:
2985
            // - mTestBuildEmailBody
2986
 
2987
            mLogger.debug("queryTest: stmt141");
2988
            phase.setPhase("getTestBuild1");
2989
            DaemonInstruction di = new DaemonInstruction( baseline, 1, true);
2990
            while ( getDaemonInst( di ) )
2991
            {
2992
                mLogger.info("queryPackageVersions test build data {}", di.pvId);
2993
 
7093 dpurdie 2994
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7048 dpurdie 2995
                if ( p == NULL_PACKAGE )
2996
                {
2997
                    mLogger.error("queryTest rset15 no data found {}", di.instruction);
2998
                    markDaemonInstCompleted( di.instruction );
2999
 
3000
                }
3001
                else
3002
                {
3003
                    packageCollection.add(p);
3004
 
3005
                    //  Set some Test information
3006
                    //  Avoid interaction with real versions
3007
                    //  Flag as not pegged - so that we test build
3008
                    p.mVersion = "0.0.0000";
3009
                    p.mTestBuildInstruction = di.instruction;
3010
                    p.addEmail(di.userEmail);
3011
                    p.mBuildReason = BuildReason.Test;
3012
                    p.mIsPegged = false;
3013
                    p.mIsNotReleased = true;
3014
                }
3015
            }
3016
        }
3017
        catch ( SQLException e )
3018
        {
3019
            handleSQLException(e, "");
3020
        }
3021
        phase.setPhase("End");
3022
    }
6914 dpurdie 3023
 
7048 dpurdie 3024
    /**
3025
     * Extract all Ripple Request package-version information
3026
     * The returned list is in daemon instruction id order - ie the first request will be first
3027
     * Only active in Daemon Mode
3028
     * 
3029
     * @param   rippleEngine        - Instance to use
3030
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
3031
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
3032
     *  
3033
     * Overridden in ReleaseManagerUtf
3034
     *  
3035
     */
3036
    protected void queryRipples(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
3037
    {
3038
        if (!mDaemon){
3039
            return;
3040
        }
3041
 
3042
        Phase phase = new Phase("rmData");
3043
        mLogger.debug("queryPackageVersions {}", mDaemon);
3044
 
3045
        try
3046
        {
3047
            // Daemon Instruction: Force Package Ripple
3048
            //  An op code of 0 means force ripple
3049
 
3050
            phase.setPhase("getDaemonInstructions1");
3051
            DaemonInstruction di = new DaemonInstruction( baseline, 0, true);
3052
            while ( getDaemonInst( di ) )
3053
            {
7093 dpurdie 3054
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7048 dpurdie 3055
                if ( p != NULL_PACKAGE )
3056
                {
3057
                    mLogger.info("queryPackageVersions forced ripple data {}", di.pvId);
3058
                    packageCollection.add(p);
3059
                    p.mForcedRippleInstruction = di.instruction;
3060
                    p.addEmail(di.userEmail);
7093 dpurdie 3061
                    p.mBuildReason = BuildReason.Forced;
7048 dpurdie 3062
                    p.mIsNotReleased = true;
3063
                }
3064
                else
3065
                {
3066
                    // discard
3067
                    markDaemonInstCompleted( di.instruction );
3068
                }
3069
            }
3070
 
3071
        }
3072
        catch ( SQLException e )
3073
        {
3074
            handleSQLException(e, "");
3075
        }
3076
        phase.setPhase("End");
3077
    }
3078
 
3079
    /** Get all build information for a single package
3080
     *  Don't use this where lots of packages are expected, but should be OK to get data for TEST, WIP and Ripples
3081
     *  
3082
     *  Does not get:
3083
     *      mBuildReason
3084
     *      mDirectlyPlanned
3085
     *  
3086
     *  @param  pvId    - Package to process
3087
     * @param rippleEngine - Ripple engine associated wit the Release
7093 dpurdie 3088
     * @param useChangeType - true: For a WIP, the change type is significant
7048 dpurdie 3089
     * @throws Exception 
3090
     *  
3091
     *  @returns a package - May be null, but this is not good
3092
     */
7093 dpurdie 3093
    Package getPackageInfo(int pvId, RippleEngine rippleEngine, boolean useChangeType) throws Exception
7048 dpurdie 3094
    {
3095
        Package p = NULL_PACKAGE;
3096
 
3097
        try
3098
        {
3099
            // Get Package info
3100
            //
3101
            mLogger.debug("getPackageInfo: stmt1");
3102
            PreparedStatement stmt1 = mConnection.prepareStatement(
3103
                    "select pv.pv_id, p.pkg_id, p.pkg_name, pv.pkg_version, " +
3104
                            " pv.v_ext, pv.change_type, pv.ripple_field," +
3105
                            " pv.major_limit, pv.minor_limit, pv.patch_limit, pv.build_number_limit," +
3106
                            " pv.modified_stamp," +
7080 dpurdie 3107
                            " release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag," +
7048 dpurdie 3108
                            " pv.build_time" +
3109
                            " from " +
3110
                            "      release_manager.package_versions pv," +
3111
                            "      release_manager.packages p" +
3112
                            " where pv.pv_id=" + pvId +
3113
                            "   and p.pkg_id=pv.pkg_id"
3114
 
3115
                    );
3116
            stmt1.setFetchSize(500);
3117
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "getPackageInfo rset1");
3118
 
3119
            //  Package must exist
3120
            if ( ! rset1.next() )
3121
            {
3122
                return NULL_PACKAGE;
3123
            }
3124
 
3125
 
3126
            int pv_id = rset1.mustGetKeyInt("pv_id");
3127
            int pkg_id = rset1.mustGetInt("pkg_id");
3128
            String pkg_name = rset1.mustGetString("pkg_name");
3129
            String pkg_version = rset1.mustGetString("pkg_version");
3130
            int buildTime = rset1.getInt("build_time", 60);
3131
 
3132
            // Previous Version of this package, without the project suffix
3133
            String pkg_prevVersion = getBaseVersionNumber(pv_id);
3134
            if ( pkg_prevVersion == null)
3135
            {
3136
                // show stopper
3137
                mLogger.error("getPackageInfo. No Previous version {}", pv_id);
3138
                throw new Exception("getPackageInfo. No Previous version" + pv_id);
3139
            }
3140
 
3141
            String v_ext = rset1.getString("v_ext","");
3142
            String change_type = rset1.getString("change_type", "P");
3143
 
3144
            char ct = 'P';
3145
 
3146
            if ( change_type.compareTo("M") == 0 )
3147
            {
3148
                ct = 'M';
3149
            }
3150
            else if ( change_type.compareTo("N") == 0 )
3151
            {
3152
                ct = 'N';
3153
            }
3154
            else if ( change_type.compareTo("P") == 0 )
3155
            {
3156
                ct = 'P';
3157
            }
3158
            else if ( change_type.compareTo("F") == 0 )
3159
            {
3160
                ct = 'F';
3161
            }
3162
 
3163
            String ripple_field = rset1.getString("ripple_field", "b");
3164
            int major_limit = rset1.getInt("major_limit", 0);
3165
            int minor_limit = rset1.getInt("minor_limit",0);
3166
            int patch_limit = rset1.getInt("patch_limit",0);
3167
            int build_number_limit = rset1.getInt("build_number_limit",0);
3168
            String vcs_tag = rset1.getString("vcsTag", "");
7093 dpurdie 3169
 
3170
            if ( useChangeType ) {
3171
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0), ct);                
3172
            } else {
3173
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
3174
            }
7048 dpurdie 3175
            p.mMajorLimit = major_limit;
3176
            p.mMinorLimit = minor_limit;
3177
            p.mPatchLimit = patch_limit;
3178
            p.mBuildLimit = build_number_limit;
3179
            p.mPrevVersion = pkg_prevVersion;
3180
            p.mBuildTime = buildTime;
3181
 
3182
            rset1.close();
3183
            stmt1.close();
3184
 
3185
            // get Package dependency info
3186
            mLogger.debug("getPackageInfo: stmt2");
3187
            PreparedStatement stmt2 = mConnection.prepareStatement(
7093 dpurdie 3188
                    "select p.pkg_name, dpv.v_ext, dpv.pv_id" +
7071 dpurdie 3189
                            " from " +
7048 dpurdie 3190
                            "     release_manager.package_versions pv,"+
3191
                            "     release_manager.package_dependencies pd," +
7093 dpurdie 3192
                            "     release_manager.package_versions dpv,"+
3193
                            "     release_manager.packages p" +
7048 dpurdie 3194
                            " where pv.pv_id=" + pvId + 
3195
                            "  and pd.pv_id=pv.pv_id"+
7093 dpurdie 3196
                            "  and dpv.pv_id=pd.dpv_id" +
3197
                            "  and pd.dpkg_id = p.pkg_id"
7048 dpurdie 3198
                    );
3199
            stmt2.setFetchSize(500);
3200
            RmResultSet rset2 = new RmResultSet(stmt2.executeQuery(), "getPackageInfo rset2");
3201
 
7081 dpurdie 3202
            while ( rset2.next() )
7048 dpurdie 3203
            {
7093 dpurdie 3204
                String dpv_name = rset2.mustGetKeyString("pkg_name");
3205
                String dpv_ext = rset2.mustGetString("v_ext");
7071 dpurdie 3206
                int    dpvId = rset2.mustGetInt("pv_id");
7048 dpurdie 3207
 
7093 dpurdie 3208
                p.mDependencyCollection.add(dpv_name + dpv_ext);
7071 dpurdie 3209
                p.mDependencyIDCollection.add(dpvId);
7048 dpurdie 3210
            }
3211
 
3212
            rset2.close();
3213
            stmt2.close();
3214
 
3215
            // get Package build info
3216
            mLogger.debug("getPackageInfo: stmt3");
3217
            PreparedStatement stmt3 = mConnection.prepareStatement(
3218
                    "select bm.bm_name, bsa.bsa_name" +
7080 dpurdie 3219
                            " from " +
3220
                            "   release_manager.package_versions pv," +
3221
                            "   release_manager.package_build_info pbi," +
3222
                            "   release_manager.build_machines bm," +
3223
                            "   release_manager.build_standards_addendum bsa " +
3224
                            " where pv.pv_id=" + pvId + 
3225
                            "   and pbi.pv_id=pv.pv_id" +
3226
                            "   and bm.bm_id=pbi.bm_id" +
3227
                            "   and bsa.bsa_id=pbi.bsa_id "
7048 dpurdie 3228
                    );
3229
            stmt3.setFetchSize(500);
3230
            RmResultSet rset3 = new RmResultSet(stmt3.executeQuery(), "getPackageInfo rset3");
3231
 
7081 dpurdie 3232
            while ( rset3.next() )
7048 dpurdie 3233
            {
3234
                String bm_name = rset3.mustGetString("bm_name");
3235
                String bsa_name = rset3.mustGetString("bsa_name");
3236
 
3237
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3238
                if ( bs.supportedBuildStandard() )
3239
                {
3240
                    p.mBuildStandardCollection.add(bs);
3241
                }
3242
            }
3243
 
3244
            rset3.close();
3245
            stmt3.close();
3246
 
3247
            // get Package unit test info
3248
            mLogger.debug("getPackageInfo: stmt4");
3249
            PreparedStatement stmt4 = mConnection.prepareStatement(
3250
                    "select pv.pv_id, tt.test_type_name" +
3251
                    "  from "+
3252
                    "       release_manager.package_versions pv,"+
3253
                    "       release_manager.unit_tests ut," +
3254
                    "       release_manager.test_types tt" +
3255
                    " where pv.pv_id=" + pvId + 
3256
                    "  and ut.pv_id=pv.pv_id" +
3257
                    "  and tt.test_type_id=ut.test_types_fk"
3258
                    );
3259
            stmt4.setFetchSize(500);
3260
            RmResultSet rset4 = new RmResultSet(stmt4.executeQuery(), "getPackageInfo rset4");
3261
 
7081 dpurdie 3262
            while ( rset4.next() )
7048 dpurdie 3263
            {
3264
                String test_type_name = rset4.mustGetString("test_type_name");
3265
                if ( test_type_name.compareTo("Autobuild UTF") == 0 )
3266
                {
3267
                    p.mHasAutomatedUnitTests = true;
3268
                }
3269
            }
3270
 
3271
            rset4.close();
3272
            stmt4.close();
3273
 
3274
            // get Package build failure info...
3275
            //      view based
3276
            mLogger.debug("getPackageInfo: stmt5");
3277
            PreparedStatement stmt5 = mConnection.prepareStatement(
7080 dpurdie 3278
                    "SELECT rc.pv_id," +
3279
                            "  u.user_email" +
3280
                            " FROM release_manager.release_content rc," +
3281
                            "  release_manager.release_tags rt," +
3282
                            "  release_manager.package_versions pv," +
3283
                            "  release_manager.autobuild_failure af," +
3284
                            "  release_manager.members_group mg," +
3285
                            "  release_manager.users u" +
3286
                            " WHERE rc.rtag_id     = " + rippleEngine.getRtagId() +
3287
                            " AND rt.rtag_id       = rc.rtag_id" +
3288
                            " AND pv.pv_id=" + pvId +
3289
                            " AND pv.pv_id         = rc.pv_id" +
3290
                            " AND af.view_id       = rc.base_view_id" +
3291
                            " AND mg.group_email_id= af.group_email_id" +
3292
                            " AND u.user_id        = mg.user_id" +
3293
                            " AND af.proj_id       = rt.proj_id"
7048 dpurdie 3294
                    );
3295
            stmt5.setFetchSize(500);
3296
            RmResultSet rset5 = new RmResultSet(stmt5.executeQuery(), "getPackageInfo rset5");
3297
 
7081 dpurdie 3298
            while ( rset5.next() )
7048 dpurdie 3299
            {
3300
                p.addEmail(rset5.getString("user_email", null));
3301
            }
3302
 
3303
            rset5.close();
3304
            stmt5.close();
3305
 
3306
            // get Package build failure info...
3307
            // package version
3308
            mLogger.debug("getPackageInfo: stmt6");
3309
            PreparedStatement stmt6 = mConnection.prepareStatement(
3310
                    "select pv.pv_id, u1.user_email as creator, u2.user_email as owner, u3.user_email as modifier" +
3311
                    " from " +
3312
                    "      release_manager.release_tags rt," +
3313
                    "      release_manager.package_versions pv," +
3314
                    "      release_manager.users u1," +
3315
                    "      release_manager.users u2," +
3316
                    "      release_manager.users u3 " +
3317
                    " where pv.pv_id=" + pvId + 
3318
                    "   and rt.rtag_id=" + rippleEngine.getRtagId() + 
3319
                    "   and pv.build_type='A'" +
3320
                    "   and pv.dlocked='A' " +
3321
                    "   and u1.user_id=pv.creator_id" +
3322
                    "   and u2.user_id=pv.owner_id" +
3323
                    "   and u3.user_id=pv.modifier_id"
3324
                    );
3325
            stmt6.setFetchSize(500);
3326
            RmResultSet rset6 = new RmResultSet(stmt6.executeQuery(), "getPackageInfo rset6");
3327
 
7081 dpurdie 3328
            while ( rset6.next() )
7048 dpurdie 3329
            {
3330
                p.addEmail( rset6.getString("creator",null));
3331
                p.addEmail( rset6.getString("owner",null));
3332
                p.addEmail( rset6.getString("modifier",null));
3333
            }
3334
 
3335
            rset6.close();
3336
            stmt6.close();
3337
 
3338
            // get Package advisory ripple info
3339
            mLogger.debug("getPackageInfo: stmt7");
3340
            PreparedStatement stmt7 = mConnection.prepareStatement(
7080 dpurdie 3341
                    "select pv.pv_id, pv.modified_stamp " +
7048 dpurdie 3342
                    " from " +
3343
                    "      release_manager.package_versions pv," +
3344
                    "      release_manager.advisory_ripple ar " +
3345
                    " where pv.pv_id = " + pvId +
3346
                    "    and ar.rtag_id=" + rippleEngine.getRtagId() +
3347
                    "    and ar.pv_id=pv.pv_id "
3348
                    );
3349
            stmt7.setFetchSize(500);
3350
            RmResultSet rset7 = new RmResultSet(stmt7.executeQuery(), "getPackageInfo rset7");
3351
 
3352
            if( rset7.next() )
3353
            {
3354
                p.mAdvisoryRipple = true;
3355
            }
3356
 
3357
            rset7.close();
3358
            stmt7.close();            
3359
 
3360
        }
3361
        catch ( SQLException e )
3362
        {
3363
            handleSQLException(e, "");
3364
        }
3365
 
3366
        return p;
3367
    }
3368
 
3369
    /**	Determine the version number of the base package
6914 dpurdie 3370
    *   Used in a ripple build to determine the base for calculating the next version number
3371
    *   Assumes that a database connection has been established
3372
    *   Used in Daemon Mode Only
3373
    *   
3374
    *   History: Used to determine the last non-rippled package, but this had issues [JATS-402]
3375
    *   This version will located the last release version with a check that it is not a WIP ( ie start with a '(' )
3376
    *   
3377
    *   @param pv_id	- The PVID of the package to process
3378
    *   @return         - The version number without a project suffix. Null on error. 0.0.0000 if no previous
3379
    *   @throws SQLException 
3380
    */
3381
    public String getBaseVersionNumber(int pv_id)
3382
    {
3383
    	String baseVersion = "0.0.0000";
3384
 
3385
    	try {
3386
    		CallableStatement stmt;
3387
			stmt = mConnection.prepareCall(
3388
					"SELECT pv_id,last_pv_id,pkg_version,v_ext,build_type, DLOCKED " +
3389
					" FROM " +
3390
					"  (SELECT build_type,last_pv_id,pv_id,pkg_version,v_ext, DLOCKED " +
3391
					"  FROM " +
3392
					"    (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 " +
3393
					"    FROM release_manager.package_versions pv " +
3394
					"    WHERE pv.PKG_ID IN " +
3395
					"      (SELECT pkg_id " +
3396
					"      FROM release_manager.package_versions pv " +
3397
					"      WHERE pv.pv_id = " + pv_id +
3398
					"      ) " +
3399
					"    ) " +
3400
					"    START WITH pv_id = " + pv_id +
3401
					"    CONNECT BY nocycle prior last_pv_id = pv_id " +
3402
					"  ) " +
3403
					" WHERE DLOCKED = 'Y' and pkg_version not like '(%' AND pv_id != " + pv_id
3404
	                   //" WHERE build_type != 'Y' and pv_id != " + pv_id
3405
			        );
3406
 
3407
			ResultSet rset = stmt.executeQuery();
3408
 
3409
			while( rset.next() )
3410
			{
3411
				// Previous Version of this package, without the project suffix
3412
				String pkg_prevVersion = rset.getString("pkg_version");
3413
				if (pkg_prevVersion != null) 
3414
				{
3415
					String pkg_prevVext = rset.getString("v_ext");
3416
					if (pkg_prevVext != null) 
3417
					{
3418
						int endindex = pkg_prevVersion.length() - pkg_prevVext.length();
3419
						if ( endindex > 0 )
3420
						{
3421
							baseVersion = pkg_prevVersion.substring(0, endindex);
3422
						}
3423
					}
3424
				}
3425
 
3426
				// Only want the first entry
3427
				break;
3428
			}
3429
 
3430
			rset.close();
3431
			stmt.close();
3432
 
3433
    	} catch (SQLException e) {
3434
    		baseVersion = null;
7048 dpurdie 3435
    		mLogger.error("Exception for getBaseVersionNumber {}", pv_id);
6914 dpurdie 3436
		}
3437
        return baseVersion;
3438
    }
3439
 
7048 dpurdie 3440
    /** Called only in escrow mode
3441
     * 
3442
     * Used to process each package in the escrow list and to locate all dependent packages - recursively.
3443
     * 
6914 dpurdie 3444
     * if checkCollection is true, checks the pv_id is in the packageCollection
3445
     * if checkCollection is false, or the pv_id is not in the collection
7048 dpurdie 3446
     *    Traverses the pv_id package dependencies
3447
     *    for each dpv.pv_id in the resultset
6914 dpurdie 3448
     *     call traverseDependencies( packageCollection, dpv.pv_id, true )
3449
     *     if the pv_id is not in the collection, add it
7048 dpurdie 3450
     * 
3451
     *   @param packageCollection   - Collection of packages being processed
3452
     *   @param pkg                 - Current package in the collection
3453
     *   @param checkCollection     - How to handle pkg not in the collection. False: Process all package dependencies. True: Skip if package is in collection
3454
     *   @param listIterator        - List iterator being used to iterate over packageCollection. Used to insert new packages
6914 dpurdie 3455
     *   
7048 dpurdie 3456
     *   This function is called recursively
6914 dpurdie 3457
     */
7048 dpurdie 3458
    private void traverseDependencies(ArrayList<Package> packageCollection, Package pkg, boolean checkCollection, ListIterator<Package> listIterator) throws SQLException, Exception
3459
    {
3460
        mLogger.debug("traverseDependencies {}", checkCollection);
6914 dpurdie 3461
        boolean pvIdInCollection = false;
3462
 
3463
        if ( checkCollection )
3464
        {
3465
            for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
3466
            {
3467
                Package p = it.next();
3468
 
3469
                if ( p.mId == pkg.mId )
3470
                {
3471
                    pvIdInCollection = true;
3472
                    break;
3473
                }
3474
            }
3475
        }
3476
 
3477
        if ( !pvIdInCollection )
3478
        {
3479
            ArrayList<Package> resultset = new ArrayList<Package>();
3480
 
3481
            try
3482
            {
3483
                PreparedStatement stmt = mConnection.prepareStatement(
3484
                        "select dpv.pv_id," +
3485
                                "p.pkg_name," + 
3486
                                "dpv.pkg_version," +
3487
                                "dpv.v_ext," + 
3488
                                "release_manager.PK_RMAPI.return_vcs_tag(dpv.pv_id) AS vcsTag" + 
3489
                                " from release_manager.package_versions pv," + 
3490
                                "release_manager.package_dependencies pd," + 
3491
                                "release_manager.package_versions dpv," + 
3492
                                "release_manager.packages p" + 
3493
                                " where pv.pv_id=" + pkg.mId + 
3494
                                "   and pd.pv_id=pv.pv_id" +
3495
                                "   and dpv.pv_id=pd.dpv_id" + 
3496
                                "   and p.pkg_id=dpv.pkg_id" + 
3497
                        " order by pv.pv_id");
3498
                stmt.setFetchSize(1000);
7023 dpurdie 3499
                RmResultSet rset = new RmResultSet(stmt.executeQuery(),"traverseDependencies");
6914 dpurdie 3500
 
3501
                while (rset.next())
3502
                {
7023 dpurdie 3503
                    int pv_id = rset.mustGetKeyInt("pv_id");
3504
                    String pkg_name = rset.mustGetString("pkg_name");
3505
                    String pkg_version = rset.mustGetString("pkg_version");
3506
                    String v_ext = rset.getString("v_ext","");
3507
                    String vcs_tag = rset.getString("vcsTag","");
6914 dpurdie 3508
 
3509
                    Package p = new Package(0, pv_id, pkg_name, pkg_version, v_ext, pkg_name + "." + pkg_version, vcs_tag, 'x');
3510
                    resultset.add(p);
3511
                    pkg.mDependencyCollection.add(p.mAlias);
3512
                }
3513
 
3514
                rset.close();
3515
                stmt.close();
3516
            }
3517
            catch ( SQLException e )
3518
            {
3519
                handleSQLException(e, "");
3520
            }
3521
 
7048 dpurdie 3522
            //  Process each dependent package
6914 dpurdie 3523
            for (Iterator<Package> it = resultset.iterator(); it.hasNext();)
3524
            {
3525
                Package r = it.next();
3526
                traverseDependencies(packageCollection, r, true, listIterator);
3527
 
3528
                pvIdInCollection = false;
3529
 
3530
                for (Iterator<Package> it2 = packageCollection.iterator(); it2.hasNext();)
3531
                {
3532
                    Package p = it2.next();
3533
 
3534
                    if (p.mId == r.mId)
3535
                    {
3536
                        pvIdInCollection = true;
3537
                        break;
3538
                    }
3539
                }
3540
 
3541
                if (!pvIdInCollection)
3542
                {
3543
                    // insert the Package immediately before the next Package returned by next
3544
                    // this does not change the next Package (if any) to be returned by next
3545
                    listIterator.add(r);
3546
                }
3547
 
3548
            }
3549
        }
7048 dpurdie 3550
    }
6914 dpurdie 3551
 
7048 dpurdie 3552
    /** Called only in escrow mode
3553
     * 
3554
     *  <p>Add build information to a Package
3555
     *  <br>Adds: bm_name and bsa_name, but only if they are supported
3556
     * 
3557
     * @param   rippleEngine    - Ripple Engine being used
3558
     * @param   p               - Package to process
3559
     * 
6914 dpurdie 3560
     */
3561
    private void queryBuildInfo(RippleEngine rippleEngine, Package p) throws SQLException, Exception
3562
    {
3563
        mLogger.debug("queryBuildInfo");
3564
 
3565
        try
3566
        {
3567
            CallableStatement stmt = mConnection.prepareCall("select bm.bm_name, bsa.bsa_name "
3568
                    + "from release_manager.package_versions pv," 
3569
                    + "     release_manager.package_build_info pbi,"
3570
                    + "     release_manager.build_machines bm," 
3571
                    + "     release_manager.build_standards_addendum bsa "
3572
                    + "where pv.pv_id=" + p.mId 
3573
                    + "   and pbi.pv_id=pv.pv_id" 
3574
                    + "   and bm.bm_id=pbi.bm_id"
3575
                    + "   and bsa.bsa_id=pbi.bsa_id " 
3576
                    + "order by pv.pv_id");
7023 dpurdie 3577
            RmResultSet rset = new RmResultSet (stmt.executeQuery(),"queryBuildInfo");
6914 dpurdie 3578
 
3579
            while (rset.next())
3580
            {
7023 dpurdie 3581
                String bm_name = rset.mustGetKeyString("bm_name");
3582
                String bsa_name = rset.mustGetString("bsa_name");
6914 dpurdie 3583
 
3584
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3585
 
3586
                if (bs.supportedBuildStandard())
3587
                {
3588
                    p.mBuildStandardCollection.add(bs);
3589
                }
3590
            }
3591
 
3592
            rset.close();
3593
            stmt.close();
3594
        }
3595
        catch ( SQLException e )
3596
        {
3597
            handleSQLException(e, "");
3598
        }
3599
 
3600
    }
3601
 
3602
    /**
3603
     * Find Package by pvid
3604
     * @param   id                  - pvid of package to locate
3605
     * @param   packageCollection   - Collection to scan
3606
     * @return  Package with the matching mID or NULL_PACKAGE if no package has the mID
3607
     */
7048 dpurdie 3608
    int findPackageLastId = 0;
7070 dpurdie 3609
    int findPackageLastIndex = 0;
7048 dpurdie 3610
    Package findPackageLastPackage = NULL_PACKAGE;
3611
 
7051 dpurdie 3612
    public Package findPackage(int id, ArrayList<Package> packageCollection)
6914 dpurdie 3613
    {
7048 dpurdie 3614
        mLogger.debug("findPackage id {}", id);
6914 dpurdie 3615
        Package retVal = NULL_PACKAGE;
7048 dpurdie 3616
 
3617
        if (findPackageLastId != 0 && findPackageLastId == id) {
3618
            mLogger.debug("findPackage id {} - cache hit", id);
3619
            retVal = findPackageLastPackage;
3620
        }
3621
        else
6914 dpurdie 3622
        {
7070 dpurdie 3623
            int index = 0;
3624
            findPackageLastIndex = -1;
3625
 
3626
            for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); index++ )
6914 dpurdie 3627
            {
7048 dpurdie 3628
                Package p = it.next();
3629
 
3630
                if ( p.mId == id )
3631
                {
3632
                    findPackageLastId = id;
3633
                    findPackageLastPackage = p;
7070 dpurdie 3634
                    findPackageLastIndex = index;
7048 dpurdie 3635
                    retVal = p;
3636
                    break;
3637
                }
6914 dpurdie 3638
            }
3639
        }
3640
 
7048 dpurdie 3641
        mLogger.debug("findPackage id {} returned {}", id, retVal.mName);
6914 dpurdie 3642
        return retVal;
3643
    }
3644
 
3645
    /**
3646
     * Find Package by package alias
3647
     * @param   alias               - alias of package to locate
3648
     * @param   packageCollection   - Collection to scan
3649
     * @return  Package with the matching mAlias or NULL_PACKAGE if no package has the mAlias
3650
     */
3651
    protected Package findPackage(String alias, ArrayList<Package> packageCollection)
3652
    {
7048 dpurdie 3653
        mLogger.debug("findPackage alias {}", alias);
6914 dpurdie 3654
        Package retVal = NULL_PACKAGE;
7070 dpurdie 3655
        int index = 0;
3656
        findPackageLastIndex = -1;
6914 dpurdie 3657
 
7070 dpurdie 3658
        for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); index++)
6914 dpurdie 3659
        {
3660
            Package p = it.next();
3661
 
3662
            if ( p.mAlias.compareTo( alias ) == 0 )
3663
            {
3664
                retVal = p;
7070 dpurdie 3665
                findPackageLastId = p.mId;
3666
                findPackageLastPackage = p;
3667
                findPackageLastIndex = index;
6914 dpurdie 3668
                break;
3669
            }
3670
        }
3671
 
7048 dpurdie 3672
        mLogger.info("findPackage alias {} returned {}", alias, retVal.mName);
6914 dpurdie 3673
        return retVal;
3674
    }
3675
 
3676
    /**only used in daemon mode to determine version existence in the database
3677
     *  1 select pkg_id from release_manager.package_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3678
     *  2 select pkg_id from release_manager.planned_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3679
     * returns true if either resultset contains one record to indicate it already exists
3680
     */
3681
    boolean queryPackageVersions(int pkg_id, String pkg_version) throws SQLException, Exception
3682
    {
3683
        mLogger.debug("queryPackageVersions");
3684
        boolean retVal = false;
3685
 
3686
        if ( mUseDatabase )
3687
        {
3688
            try
3689
            {
3690
                mLogger.info("queryPackageVersions release_manager.package_versions");
3691
                CallableStatement stmt1 = mConnection.prepareCall(
3692
                    "select pkg_id" +
3693
                    " from release_manager.package_versions" +
3694
                    " where pkg_id=" + pkg_id + 
3695
                    " and pkg_version='" + pkg_version + "'");
3696
 
3697
                ResultSet rset1 = stmt1.executeQuery();
3698
                int rsetSize = 0;
3699
 
3700
                while( rset1.next() )
3701
                {
3702
                    rsetSize++;
3703
                }
3704
 
3705
                rset1.close();
3706
                stmt1.close();
3707
 
3708
                if ( rsetSize > 1 )
3709
                {
7048 dpurdie 3710
                    String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3711
                    mLogger.error(msg);
6914 dpurdie 3712
                    // show stopper
7048 dpurdie 3713
                    throw new Exception(msg);
6914 dpurdie 3714
                }
3715
 
3716
                if ( rsetSize == 1 )
3717
                {
3718
                    retVal = true;
3719
                }
3720
                else
3721
                {
3722
                    mLogger.info("queryPackageVersions release_manager.planned_versions");
3723
                    CallableStatement stmt2 = mConnection.prepareCall(
3724
                        "select pkg_id" +
3725
                        " from release_manager.planned_versions" +
3726
                        " where pkg_id=" + pkg_id + 
3727
                        " and pkg_version='" + pkg_version + "'");
3728
                    ResultSet rset2 = stmt2.executeQuery();
3729
                    rsetSize = 0;
3730
 
3731
                    while( rset2.next() )
3732
                    {
3733
                        rsetSize++;
3734
                    }
3735
 
3736
                    rset2.close();
3737
                    stmt2.close();
3738
 
3739
                    if ( rsetSize > 1 )
3740
                    {
7048 dpurdie 3741
                        String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3742
                        mLogger.error(msg);
6914 dpurdie 3743
                        // show stopper
7048 dpurdie 3744
                        throw new Exception(msg);
6914 dpurdie 3745
                    }
3746
 
3747
                    if ( rsetSize == 1 )
3748
                    {
3749
                        retVal = true;
3750
                    }
3751
                }
3752
            }
3753
            catch ( SQLException e )
3754
            {
3755
                handleSQLException(e, "");
3756
            }
3757
        }
3758
 
7048 dpurdie 3759
        mLogger.info("queryPackageVersions returned {}", retVal);
6914 dpurdie 3760
        return retVal;
3761
    }
3762
 
3763
    /**
3764
     * Determine the set of packages that have been excluded from the build 
3765
     * These are packages that have been marked as do_not_ripple 
3766
     *  
3767
     * Overridden in ReleaseManagerUtf
3768
     * 
3769
     * @param buildExclusionCollection
3770
     * @param baseline The rtag_id of the release to examine
3771
     * 
3772
     * @exception SQLException
3773
     * @exception Exception
3774
     */
3775
    public void queryBuildExclusions(List<BuildExclusion> buildExclusionCollection, int baseline) throws SQLException, Exception
3776
    {
7048 dpurdie 3777
        mLogger.debug("queryBuildExclusions {}", baseline);
6914 dpurdie 3778
 
3779
        try
3780
        {
3781
            PreparedStatement stmt = mConnection.prepareStatement(
3782
                    "select pv_id, root_pv_id, root_cause" +
3783
                    " from release_manager.do_not_ripple" + 
3784
                    " where rtag_id=" + baseline);
3785
            stmt.setFetchSize(1000);
7023 dpurdie 3786
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryBuildExclusions");
6914 dpurdie 3787
 
3788
            while( rset.next() )
3789
            {
7023 dpurdie 3790
                int pvId = rset.mustGetKeyInt("pv_id");
3791
                int rootPvId = rset.getInt("root_pv_id", -1);
3792
                String rootCause = rset.getString("root_cause", null);
6914 dpurdie 3793
 
3794
                // force email notification by using a zero test build instruction
3795
                BuildExclusion buildExclusion = new BuildExclusion(pvId, rootPvId, rootCause, 0);
7032 dpurdie 3796
                buildExclusion.setImported();
6914 dpurdie 3797
                buildExclusionCollection.add(buildExclusion);
3798
            }
3799
 
3800
            rset.close();
3801
            stmt.close();
3802
        }
3803
        catch ( SQLException e )
3804
        {
3805
            handleSQLException(e, "");
3806
        }
3807
    }
3808
 
3809
    /**
7032 dpurdie 3810
     * Execute the Exclude_Indirect_From_Build stored procedure
6914 dpurdie 3811
     *  Note: Execute_Indirect_From_Build will delete matching do_not_ripple
3812
     *        rows prior to an insertion - this is crucial!!
7032 dpurdie 3813
     *        
3814
     * Note: The name 'Execute_Indirect_From_Build' is misleading as it appears to be used for both direct and indirect
3815
     *       exclusions.
3816
     * 
6914 dpurdie 3817
     * @param hasConnection        IN True. Use existing connection and will not commit the operation
3818
     * @param packageVersionId     IN passed to Exclude_Indirect_From_Build
3819
     * @param packageVersion       IN passed to Exclude_Indirect_From_Build
3820
     * @param rtagId               IN passed to Exclude_Indirect_From_Build
3821
     * @param rootPvId             IN passed to Exclude_Indirect_From_Build
3822
     * @param rootCause            IN passed to Exclude_Indirect_From_Build
3823
     * @param rootFile             IN passed to Exclude_Indirect_From_Build
3824
     * @param supercede            IN checks for a row with a matching packageVersionId and rtagId when false
3825
     *                                such a row will prevent the execution of Exclude_Indirect_From_Build
3826
     * @param testBuildInstruction IN will prevent the execution of Exclude_Indirect_From_Build true
3827
     * 
3828
     * @exception SQLException
3829
     * @exception Exception
3830
     */
3831
    public void excludeFromBuild(
3832
            boolean hasConnection, 
3833
            int packageVersionId, 
3834
            String packageVersion, 
3835
            int rtagId,
3836
            String rootPvId, 
3837
            String rootCause,
3838
            String rootFile,
3839
            boolean supercede, Boolean testBuildInstruction) throws SQLException, Exception
3840
    {
7048 dpurdie 3841
        mLogger.debug("excludeFromBuild {}", packageVersionId);
6914 dpurdie 3842
 
3843
        //  If a Test Build, then don't excluded package
3844
        if ( testBuildInstruction )
3845
        {
3846
            return;
3847
        }
3848
 
3849
        if ( mUseDatabase )
3850
        {
3851
            try
3852
            {
3853
                if (!hasConnection)
3854
                    connect();
3855
 
3856
                boolean exist = false;
7032 dpurdie 3857
                boolean dbIsIndirect = false;
3858
                boolean entryIsIndirect = (rootPvId != null);
6914 dpurdie 3859
 
3860
                if ( !supercede )
3861
                {
3862
                    // do not exclude a package already excluded ie let the first build failure count
3863
                    // there is a window of opportunity here, but it is worth doing
3864
                    // scenario 1
3865
                    //      1 this query indicates no build failure exists on this version
3866
                    //      2 another build machine reports a build failure on this version
3867
                    //      3 this is then overridden by this thread
3868
                    // does not matter
3869
                    // doing this works well for the following
3870
                    // scenario 2
3871
                    //      1 this query (run by a slave) indicates no build failure exists on this version
3872
                    //      2 build failure is reported
3873
                    //      3 master build machine detects slave in state waiting
3874
                    //      4 master daemon discovers slave did not deliver artifacts
3875
                    //      5 master daemon is prevented from overriding the build failure
7032 dpurdie 3876
                    //
3877
                    // Another complication
3878
                    //  If this is a direct exclusion (rootPvid) is null and the entry in the table is an indirect exclusion
3879
                    //  then we should delete the indirect exclusion and replace it with a direct exclusion
3880
                    //
3881
                    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 3882
                    ResultSet rset = stmt.executeQuery();
3883
 
3884
                    while( rset.next() )
3885
                    {
3886
                        exist = true;
7032 dpurdie 3887
                        rset.getInt("root_pv_id");
3888
                        dbIsIndirect = ! rset.wasNull();
3889
 
3890
                        // Override an indirect database entry with a direct exclusion
3891
                        if ( dbIsIndirect && ! entryIsIndirect ) {
3892
                            exist = false;
3893
                        }
3894
 
6914 dpurdie 3895
                        break;
3896
                    }
3897
 
3898
                    rset.close();
3899
                    stmt.close();
3900
                }
3901
 
3902
                if ( !exist )
3903
                {
3904
                    CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD(?,?,?,?,?,?,?); end;" );
3905
                    stmt.registerOutParameter( 1, Types.INTEGER);
3906
                    stmt.setInt    ( 2, packageVersionId );
3907
                    stmt.setString ( 3, packageVersion );
3908
                    stmt.setInt    ( 4, rtagId );
3909
                    stmt.setString ( 5, "buildadm" );
3910
                    stmt.setString ( 6, rootPvId);
3911
                    stmt.setString ( 7, rootCause);
3912
                    stmt.setString ( 8, rootFile);
3913
                    stmt.executeUpdate();
3914
                    int result = stmt.getInt( 1 );
3915
 
3916
                    if ( result != 0 )
3917
                    {
3918
                        // flag build failure
7048 dpurdie 3919
                        mLogger.error( "excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned {}",  result );
6914 dpurdie 3920
                        throw new Exception("excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned " + result);
3921
                    }
3922
                    stmt.close();
3923
                    if (!hasConnection )
3924
                        commit();
3925
                }
3926
            }
3927
            catch ( SQLException e )
3928
            {
3929
                handleSQLException(e, "");
3930
            }
3931
            finally
3932
            {
3933
                // this block is executed regardless of what happens in the try block
3934
                // even if an exception is thrown
3935
                // ensure disconnect
3936
                if (!hasConnection )
3937
                    disconnect();
3938
            }
3939
        }
3940
    }
3941
 
3942
    /**
3943
     * Removes an excluded package from the do_not_ripple table, thereby including the package back into the build set.
3944
     * The method does not remove packages that were manually added to the DNR table, as those
3945
     * packages are not in the domain of the buildtool.
3946
     * 
3947
     * @param packageVersionId Packages PVID
3948
     * @param rtagId           The RTAG id of the release to consider
3949
     * 
3950
     * @exception SQLException
3951
     * @exception Exception
3952
     */
3953
 
3954
    public void includeToBuild(int packageVersionId, int rtagId) throws SQLException, Exception
3955
    {
7048 dpurdie 3956
        mLogger.debug("includeToBuild {}", packageVersionId);
6914 dpurdie 3957
        if ( mUseDatabase )
3958
        {
3959
            try
3960
            {
3961
                CallableStatement stmt = mConnection.prepareCall(
3962
                    "delete from release_manager.do_not_ripple " +
3963
                    "  where rtag_id=" + rtagId + 
3964
                    "  and pv_id=" + packageVersionId +
3965
                    "  and (root_pv_id is not NULL or root_cause is not NULL or root_file is not NULL)"
3966
                    );
3967
                stmt.executeUpdate();
3968
                stmt.close();
3969
            }
3970
            catch ( SQLException e )
3971
            {
3972
                handleSQLException(e, "");
3973
            }
3974
        }
3975
    }
3976
 
3977
 
3978
 
3979
 
3980
    /**queries the RUN_LEVEL table using the rcon_id primary key
3981
     * handles database connection and disconnection
3982
     * returns the current_build_files
3983
     * implements the sequence diagram consume build files 
3984
     *  
3985
     * Used by the Slave Daemon
3986
     * 
3987
     *  @param rcon_id - My release config id
3988
     *  @return The buildFile content. Will be null if none is found
3989
     */
3990
    public String queryBuildFile(int rcon_id) throws SQLException, Exception
3991
    {
3992
        String buildFile = null;
3993
 
7048 dpurdie 3994
        mLogger.debug("queryRunLevel 1 rcon_id {}", rcon_id);
6914 dpurdie 3995
        if ( !mUseDatabase )
3996
        {
3997
            mLogger.info("queryRunLevel 1 !mUseDatabase");
3998
            buildFile = "unit test build file content";
3999
        }
4000
        else
4001
        {
4002
            try
4003
            {
4004
                connect();
4005
                CallableStatement stmt = mConnection.prepareCall("select current_build_files from release_manager.run_level where rcon_id=" + rcon_id);
4006
                ResultSet rset = stmt.executeQuery();
4007
                int rsetSize = 0;
4008
 
4009
                while( rset.next() )
4010
                {
4011
                    rsetSize++;
4012
                    buildFile = rset.getString("current_build_files");
4013
                }
4014
 
4015
                if ( rsetSize > 1 )
4016
                {
7033 dpurdie 4017
                    mLogger.error("queryRunLevel 1 rsetSize > 1");
6914 dpurdie 4018
                    // show stopper
4019
                    throw new Exception("queryRunLevel 1 rsetSize > 1");
4020
                }
4021
 
4022
                rset.close();
4023
                stmt.close();
4024
            }
4025
            catch ( SQLException e )
4026
            {
4027
                handleSQLException(e, "");
4028
            }
4029
            finally
4030
            {
4031
                // this block is executed regardless of what happens in the try block
4032
                // even if an exception is thrown
4033
                // ensure disconnect
4034
                disconnect();
4035
            }
4036
        }
4037
 
4038
        return buildFile;
4039
    }
4040
 
4041
    /** Updates mRunLevelCollection
4042
     *  Removes all elements from mRunLevelCollection, then queries the Database
4043
     *  and re-populates the structure.
4044
     *  
4045
     *  Used to determine which slave daemons the master needs to wait upon.
4046
     *  
4047
     *  Ignores entries that are disabled
4048
     *  Ignore entries that have been 'unlinked' - they have no active machine configuration
4049
     *
4050
     *   @param	rtag_id	- Release Tag
4051
     *  
4052
     *	Used by the Master Daemon 
4053
     * 	Overridden in ReleaseManagerUtf 
4054
     */
4055
    public void queryRunLevel(final int rtag_id) throws SQLException, Exception
4056
    {
7048 dpurdie 4057
        mLogger.debug("queryRunLevel 2 rtag_id {}", rtag_id);
6914 dpurdie 4058
 
4059
        mRunLevelCollection.clear();
4060
 
4061
        try
4062
        {
4063
            connect();
4064
            CallableStatement stmt = mConnection.prepareCall(
4065
                    "SELECT rl.rcon_id," +
4066
                    "  rl.current_run_level," +
4067
                    "  NVL(rl.pause,0) as pause," +
4068
                    "  rc.daemon_mode," +
4069
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4070
                    " FROM release_manager.release_config rc," +
4071
                    "     release_manager.run_level rl" +
4072
                    " WHERE rc.rtag_id = " + rtag_id +
4073
                    " AND   rl.rcon_id = rc.rcon_id" +
4074
                    " AND   rc.bmcon_id is not NULL");
4075
            stmt.setFetchSize(20);
7023 dpurdie 4076
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryRunLevel 2");
6914 dpurdie 4077
            int rcon_id = 0;
4078
            int current_run_level = 0;
4079
            String modeString;
4080
            char mode;
4081
            int pause = 0;
4082
            int buildFilePresent = 0;
4083
 
4084
            while( rset.next() )
4085
            {
7023 dpurdie 4086
                rcon_id = rset.mustGetKeyInt("rcon_id");
4087
                modeString = rset.mustGetString("daemon_mode");
6914 dpurdie 4088
                mode = modeString.charAt(0);
7023 dpurdie 4089
                buildFilePresent = rset.getInt("bfPresent",0);
4090
                current_run_level = rset.getInt("current_run_level", BuildState.DB_IDLE.toValue());
6914 dpurdie 4091
 
4092
                //
4093
                //  Pause: null -> 0 == Run
4094
                //         1         == Pause
4095
                //         2         == Disabled
4096
                //
7023 dpurdie 4097
                pause = rset.getInt("pause", 0);
6914 dpurdie 4098
 
4099
                //  Ignore disabled entries
4100
                if ( pause <= 1 )
4101
                {
4102
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, mode, buildFilePresent);
4103
                    mRunLevelCollection.add(runLevel);
4104
                }
4105
            }
4106
 
4107
            rset.close();
4108
            stmt.close();
4109
        }
4110
        catch ( SQLException e )
4111
        {
4112
            handleSQLException(e, "");
4113
        }
4114
        finally
4115
        {
4116
            // this block is executed regardless of what happens in the try block
4117
            // even if an exception is thrown
4118
            // ensure disconnect
4119
            disconnect();
4120
        }
4121
    }
4122
 
4123
    /**
4124
     * Removes all elements and then re-populates mRunLevelCollection
4125
     * 
4126
     * Queries the RM database to determine the run_level of the current daemon.
4127
     * Populates the mRunLevelCollection with the query result set 
4128
     *  
4129
     * Used to determine if the (Slave) thread should still be running
4130
     *  
4131
     * Used by the Slave Daemon 
4132
     * Overridden in ReleaseManagerUtf 
4133
     * 
4134
     * @param rcon_id     Identify the Release_Config table entry for the daemon
4135
     * @param hostname    Name of the host machine
4136
     * @param daemon_mode Specifies the current daemon type
4137
     * 
4138
     * @exception SQLException
4139
     *                      Database connection errors
4140
     *                      Bad SQL statement
4141
     * @exception Exception Too many rows extracted from the database
4142
     *                      Empty(NULL) data in database
4143
     */
4144
    public void querySingleRunLevel(final int rcon_id, String hostname, char daemon_mode) throws SQLException, Exception
4145
    {
7048 dpurdie 4146
        mLogger.debug("querySingleRunLevel rcon_id {}", rcon_id);
6914 dpurdie 4147
        mRunLevelCollection.clear();
4148
 
4149
        try
4150
        {
4151
            connect();
4152
 
4153
            CallableStatement stmt = mConnection.prepareCall(
4154
                    "select rl.rcon_id, "+
4155
                    "  rl.current_run_level,"+
4156
                    "  NVL(rl.pause,0) as pause," +
4157
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4158
                    " from release_manager.run_level rl,"+
4159
                    "   release_manager.release_config rc" +
4160
                    " where rl.rcon_id = rc.rcon_id" +
4161
                    "   AND rc.rcon_id=" + rcon_id +
4162
                    "   AND rc.bmcon_id is not NULL" +
4163
                    "   AND rc.daemon_mode='" + daemon_mode + "'" +
4164
                    "   AND UPPER(rc.daemon_hostname)=UPPER('" + hostname + "')"
4165
                    );
7023 dpurdie 4166
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"querySingleRunLevel");
6914 dpurdie 4167
            int rsetSize = 0;
4168
            int current_run_level = 0;
4169
            int pause = 0;
4170
            int buildFilePresent = 0;
4171
 
4172
            while( rset.next() )
4173
            {
4174
                rsetSize++;
7023 dpurdie 4175
                current_run_level = rset.mustGetInt("current_run_level");
4176
                buildFilePresent = rset.getInt("bfPresent",0);
6914 dpurdie 4177
 
4178
                //
4179
                //  Pause: null -> 0 == Run
4180
                //         1         == Pause
4181
                //         2         == Disabled
4182
                //
7023 dpurdie 4183
                pause = rset.getInt("pause",0);
6914 dpurdie 4184
 
4185
                //  Ignore disabled daemons
4186
                if ( pause <= 1)
4187
                {
4188
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, daemon_mode, buildFilePresent);
4189
                    mRunLevelCollection.add(runLevel);
4190
                }
4191
            }
4192
 
4193
            rset.close();
4194
            stmt.close();
4195
 
4196
            //  Must have no more than one record
4197
            //  Will have none if this daemon is no longer a part of the build set
4198
            //
4199
            if ( rsetSize > 1 )
4200
            {
4201
                //  show stopper
4202
                //  More rows than expected returned from the database
7033 dpurdie 4203
                mLogger.error("querySingleRunLevel rsetSize > 1");
6914 dpurdie 4204
                throw new Exception("querySingleRunLevel rsetSize > 1");
4205
            }
4206
        }
4207
        catch ( SQLException e )
4208
        {
4209
            handleSQLException(e, "");
4210
        }
4211
        finally
4212
        {
4213
            // this block is executed regardless of what happens in the try block
4214
            // even if an exception is thrown
4215
            // ensure disconnect
4216
            disconnect();
4217
        }
4218
    }
4219
 
4220
    /**Queries the RUN_LEVEL_SCHEDULE table to determine if we can proceed
4221
     * <br>Will not proceed if:
4222
     *      <br>- Inside a scheduled downtime
4223
     *      <br>- Indefinite pause present
4224
     * 
4225
     * <br>Should delete rows with a non NULL indefinite pause (but doesn't appear too)
4226
     *  
4227
     * <br>Assumes connection to database has been established
4228
     * 
4229
     * @param   resumeTime.value  Returns date-time when daemon can run again 
4230
     * 
4231
     * @return  False: if a row in the query result set indicates build service downtime is scheduled
4232
     *      <br>False: if a row in the query result set has a non NULL indefinite_pause
4233
     */
4234
    public boolean queryRunLevelSchedule(MutableDate resumeTime) throws SQLException, Exception
4235
    {
4236
        mLogger.debug("queryRunLevelSchedule");
4237
        boolean retVal = true;
4238
 
4239
        if ( mUseDatabase )
4240
        {
4241
            //
4242
            //  Clean up the run_level_schedule table by deleting out of date entries
4243
            //
4244
            try
4245
            {
4246
                CallableStatement stmt = mConnection.prepareCall( "BEGIN PK_BUILDAPI.DELETE_OUT_OF_DATE_SCHEDULE;   END;" );
4247
                stmt.executeUpdate();
4248
                stmt.close();
4249
                commit();
4250
            }
4251
            catch ( SQLException e )
4252
            {
4253
                handleSQLException(e, ":1");
4254
            }
4255
 
4256
            try
4257
            {
4258
                //  Extract info from the database
4259
                //
4260
                CallableStatement stmt = mConnection.prepareCall(
4261
                        "select scheduled_pause, scheduled_resume, repeat, indefinite_pause" + 
4262
                        " from release_manager.run_level_schedule");
4263
                ResultSet rset = stmt.executeQuery();
4264
                Date now = new Date();
4265
 
4266
                //
4267
                //  Scan the database information and determine if there is any reason
4268
                //  to pause. Terminate the loop on the first excuse to pause
4269
                //  as indefinite pause may have multiple (lots) of entries in the data
4270
                //  base.
4271
                //
4272
                while( retVal && rset.next() )
4273
                {
4274
                    //
4275
                    //  Examine the current row from the data base
4276
                    //  Expect one of two forms:
4277
                    //    1) scheduled_pause
4278
                    //       Must also have a scheduled_resume and a repeat
4279
                    //    2) indefinite_pause
4280
                    //
4281
 
4282
                    //  Look for scheduled_pause style of entry
4283
                    //
4284
                    Timestamp sp = rset.getTimestamp("scheduled_pause");
4285
                    if ( sp != null )
4286
                    {
4287
                        Date scheduledPause = new Date( sp.getTime() );
4288
                        Timestamp sr = rset.getTimestamp("scheduled_resume");
4289
 
4290
                        if ( sr != null )
4291
                        {
4292
                            Date scheduledResume = new Date( sr.getTime() );
4293
                            int repeat = rset.getInt("repeat");
7048 dpurdie 4294
                            mLogger.info("queryRunLevelSchedule repeat {}", repeat);
6914 dpurdie 4295
 
4296
                            //
4297
                            //  Have scheduled_pause and scheduled_resume
4298
                            //  Examine the repeat field and determine how these are used
4299
                            //  Supported repeat:
4300
                            //      0:Once Only
4301
                            //      1:Daily           Year, Month and Day information is ignored
4302
                            //      7:Weekly          Only day of week is utilized
4303
                            //
4304
                            if ( !rset.wasNull() )
4305
                            {
4306
                                GregorianCalendar startOfDowntime = new GregorianCalendar();
4307
                                GregorianCalendar endOfDowntime = new GregorianCalendar();
4308
                                GregorianCalendar clock = new GregorianCalendar();
4309
 
4310
                                switch( repeat )
4311
                                {
4312
                                    case 0:
4313
                                        // Once Only
4314
                                        // Simple check between start and end date-times
4315
                                        if ( scheduledPause.before(now) && scheduledResume.after(now) )
4316
                                        {
4317
                                            mLogger.warn("queryRunLevelSchedule one off scheduled downtime");
4318
                                            resumeTime.value = scheduledResume;
4319
                                            retVal = false;
4320
                                        }
4321
                                        break;
4322
 
4323
                                    case 1:
4324
 
4325
                                        //  Daily
4326
                                        //  Create start and end times, then massage some fields
4327
                                        //  to reflect todays date.
4328
                                        //  Use start and end times from scheduled_pause and scheduled_resume
4329
                                        //
4330
 
4331
                                        startOfDowntime.setTime(scheduledPause);
4332
                                        endOfDowntime.setTime(scheduledResume);
4333
                                        clock.setTime(now);
4334
 
4335
                                        // Force date fields to todays date
4336
                                        endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4337
                                        startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4338
 
4339
                                        if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4340
                                        {
4341
                                            mLogger.warn("queryRunLevelSchedule daily scheduled downtime");
4342
                                            resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4343
                                            retVal = false;
4344
                                        }
4345
                                        break;
4346
 
4347
                                    case 7:
4348
 
4349
                                        // Weekly
4350
                                        // Create start and end times, then massage some fields
4351
                                        // to reflect todays date.
4352
                                        // Use DayOfWeek and time from scheduled_pause
4353
                                        // Use time from scheduled_resume
4354
                                        //
4355
                                        startOfDowntime.setTime(scheduledPause);
4356
                                        endOfDowntime.setTime(scheduledResume);
4357
                                        clock.setTime(now);
4358
 
4359
                                        // Only interested in one day of the week
4360
                                        if ( startOfDowntime.get(Calendar.DAY_OF_WEEK) == clock.get(Calendar.DAY_OF_WEEK) )
4361
                                        {
4362
                                            endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4363
                                            startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4364
 
4365
                                            if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4366
                                            {
4367
                                                mLogger.warn("queryRunLevelSchedule weekly scheduled downtime");
4368
                                                resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4369
                                                retVal = false;
4370
                                            }
4371
                                        }
4372
                                        break;
4373
 
4374
                                   default:
4375
                                       //
4376
                                       //   Unexpected value
4377
                                       break;
4378
                                }
4379
                            }
4380
                        }
4381
                    }
4382
 
4383
                    //
4384
                    //  Look for indefinite_pause style of entry
4385
                    //  Note: due to an implementation error there may be many
4386
                    //        rows that match. We only need one. The scan will
4387
                    //        be terminated if we find any
4388
                    //  
4389
                    //
4390
                    String ip = rset.getString("indefinite_pause");
4391
                    if ( ip != null )
4392
                    {
4393
                        // indefinite pause is non null
4394
                        mLogger.warn("queryRunLevelSchedule indefinite pause");
4395
                        GregorianCalendar clock = new GregorianCalendar();
4396
                        clock.setTime(now);
4397
                        // wait a minute
4398
                        resumeTime.value.setTime(clock.getTimeInMillis() + 60000);
4399
                        retVal = false;
4400
                    }
4401
                }
4402
 
4403
                rset.close();
4404
                stmt.close();
4405
            }
4406
            catch ( SQLException e )
4407
            {
4408
                handleSQLException(e, ":2");
4409
            }
4410
        }
4411
 
7048 dpurdie 4412
        mLogger.info("queryRunLevelSchedule returning {}", retVal);
6914 dpurdie 4413
        return retVal;
4414
    }
4415
 
4416
    /**persists the runLevel in the RUN_LEVEL table for the rcon_id primary key
4417
     * 
4418
     * Overridden in the UTF
4419
     * 
4420
     * @param   rcon_id         Identifies the Release Connection (daemon)
4421
     * @param   runLevel        The run level to set
4422
     * 
4423
     */
4424
    public void updateCurrentRunLevel(final int rcon_id, final int runLevel) throws SQLException, Exception
4425
    {
4426
        mLogger.debug("updateCurrentRunLevel");
4427
 
4428
        try
4429
        {
4430
            connect();
4431
 
7048 dpurdie 4432
            mLogger.warn("updateCurrentRunLevel: Set Runlevel:{}, rconId:{}", runLevel, rcon_id);
6914 dpurdie 4433
            PreparedStatement stmt = mConnection.prepareCall("update release_manager.run_level set current_run_level=" + runLevel + ", keep_alive=SYSDATE where rcon_id=" + rcon_id);
4434
            stmt.executeUpdate();
4435
            stmt.close();
4436
 
4437
            mLogger.info("updateCurrentRunLevel: committing");
4438
            commit();
4439
            mLogger.info("updateCurrentRunLevel: committed");
4440
        }
4441
        catch ( SQLException e )
4442
        {
4443
            handleSQLException(e, "");
4444
        }
4445
        finally
4446
        {
4447
            // this block is executed regardless of what happens in the try block
4448
            // even if an exception is thrown
4449
            // ensure disconnect
4450
            disconnect();
4451
        }
4452
 
4453
    }
4454
 
4455
    /** Report the current build plan
4456
     *  This is only for display purposes
4457
     *  Assume a connection has been established. Will not commit if the operation is covered by the Mutex
4458
     *  
4459
     * @param mRtagId - Release we are building
4460
     * @param mBuildOrder - Ordered list of PackageVersions that we plan to build
4461
     * @throws Exception 
4462
     * @throws SQLException 
4463
     */
7079 dpurdie 4464
    public void reportPlan(int mRtagId, ArrayList<PlannedPackage> mBuildOrder) throws SQLException, Exception {
7048 dpurdie 4465
        mLogger.debug("reportPlan {}", mRtagId);
6914 dpurdie 4466
 
4467
        if ( mUseDatabase )
4468
        {
4469
            try
4470
            {
7079 dpurdie 4471
                Iterator<PlannedPackage> it = mBuildOrder.iterator();
6914 dpurdie 4472
                int fragment = 0;
4473
                CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.set_build_plan(?,?,?)" );
4474
 
4475
                do {
4476
                    //
4477
                    // Generate a comma separated list of PVIDs
4478
                    // Limit the length of the string since we can only pump 4000 chars into a string
4479
                    // Allow 10 chars per PV_ID
4480
                    //
4481
                    StringBuilder pvList = new StringBuilder();
4482
                    String joiner = "";
4483
 
4484
                    while ( pvList.length() < 3000  && it.hasNext() )
4485
                    {
7079 dpurdie 4486
                        PlannedPackage p = it.next();
6914 dpurdie 4487
                        pvList.append(joiner);
7079 dpurdie 4488
                        pvList.append(p.mPkg.mId);
6914 dpurdie 4489
                        joiner = ",";
4490
                    }
4491
 
4492
                    //  Terminate if we have nothing to add and its not the first pass
4493
                    if (pvList.length() <= 0 && fragment != 0)
4494
                    {
4495
                        break;
4496
                    }
4497
 
4498
                    //
4499
                    //  Insert data - one fragment at a time
4500
                    //
4501
                    stmt.setInt    ( 1, mRtagId );
4502
                    stmt.setInt    ( 2, fragment );
4503
                    stmt.setString ( 3, pvList.toString() );
4504
                    stmt.executeUpdate();
4505
                    fragment++;
4506
 
4507
                } while(true);
4508
 
4509
                stmt.close();
4510
 
4511
                //  Commit only if not covered by the Mutex
4512
                if ( ! mDoNotCommit )
4513
                    commit();
4514
            }
4515
            catch ( SQLException e )
4516
            {
4517
                handleSQLException(e, "");
4518
            }
4519
            finally
4520
            {
4521
                // this block is executed regardless of what happens in the try block
4522
                // even if an exception is thrown
4523
            }
4524
        }
4525
    }
4526
 
4527
    public void updateBuildDuration(int pvId, int duration) throws Exception {
7048 dpurdie 4528
        mLogger.debug("updateBuildDuration {}:{}", pvId, duration);
6914 dpurdie 4529
        if ( mUseDatabase )
4530
        {
4531
            try
4532
            {
4533
                connect();
4534
 
4535
                String sql = "update release_manager.package_versions set BUILD_TIME = ? where pv_id = ?";
4536
 
4537
                PreparedStatement stmt = mConnection.prepareStatement(sql);
4538
                stmt.setLong( 1,duration );
4539
                stmt.setLong( 2,pvId );
4540
                stmt.executeUpdate();
4541
                stmt.close();
4542
                commit();
4543
            }
4544
            catch ( SQLException e )
4545
            {
4546
                handleSQLException(e, "");
4547
            }
4548
            finally
4549
            {
4550
                disconnect();
4551
            }
4552
        }
4553
    }
4554
 
4555
    /**  Set RippleStop flag to 'w' for waiting
4556
     *  Indicated that the build system will Ripple the package, when the user confirms that it can be done
4557
     *  Assume database connection has been established
4558
     * @param mRtagId 
4559
     * 
4560
     * @param pkg - Package being processed
4561
     * @throws Exception 
4562
     */
4563
    public void setRippleStopWait(int mRtagId, Package pkg) throws Exception {
4564
 
4565
        // Use a stored procedure as it will also do logging
4566
        mLogger.debug("setRippleStopWait");
4567
        if ( mUseDatabase )
4568
        {
4569
            try
4570
            {
4571
                // "BEGIN  PK_PACKAGE.Set_Ripple_Stop( :PV_ID, :RTAG_ID, :USER_ID, :RSTATE );  END;"
4572
 
4573
                CallableStatement stmt = mConnection.prepareCall( "BEGIN  PK_PACKAGE.Set_Ripple_Stop( ?, ?, ?, 'w' );  END;" );
4574
                stmt.setInt(1, pkg.mId);        // PVID
4575
                stmt.setInt(2, mRtagId);        // RTAG ID 
4576
                stmt.setInt(3, 3768);           // USER ID - buildadm ( Yes I know its ugly )
4577
                stmt.executeUpdate();
4578
                stmt.close();
4579
            }
4580
            catch ( SQLException e )
4581
            {
4582
                handleSQLException(e, "");
4583
            }
4584
        }
4585
 
4586
    }
4587
 
4588
}
4589