Subversion Repositories DevTools

Rev

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