Subversion Repositories DevTools

Rev

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