Subversion Repositories DevTools

Rev

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