Subversion Repositories DevTools

Rev

Rev 7169 | Rev 7180 | 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 ) {
7176 dpurdie 510
                mLogger.error("disconnectForPlanning. IllegalMonitorStateException exception {}", e);
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) {
7176 dpurdie 552
                mLogger.error("disconnect. IllegalMonitorStateException exception {}", e);
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");
7176 dpurdie 602
                mLogger.warn("claimMutex calling stmt.executeUpdate");
6914 dpurdie 603
                stmt.executeUpdate();
7176 dpurdie 604
                mLogger.warn("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;
7176 dpurdie 632
                mLogger.warn("releaseMutex calling commit");
6914 dpurdie 633
                commit();
7176 dpurdie 634
                mLogger.warn("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
    {
7176 dpurdie 806
        mLogger.warn("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
    {
7176 dpurdie 866
        mLogger.warn("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
    {
7176 dpurdie 912
        mLogger.warn("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
 
7176 dpurdie 1546
        mLogger.debug("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
 
7176 dpurdie 1588
        mLogger.debug("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
    {
7176 dpurdie 1928
        mLogger.warn("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
        }
7176 dpurdie 1980
        mLogger.debug("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
 
7176 dpurdie 2053
        mLogger.debug("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;
7176 dpurdie 2140
                    mLogger.warn("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
                    {
7176 dpurdie 2148
                        mLogger.warn("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
 
7176 dpurdie 2175
        mLogger.debug("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
 
7176 dpurdie 2231
                mLogger.debug("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
 
7176 dpurdie 2332
                mLogger.debug("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" +
7176 dpurdie 2455
                    " AND UPPER(rc.daemon_hostname) = UPPER(?)" +
6914 dpurdie 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" +
7176 dpurdie 2460
                    " AND rl.rcon_id in (?)"
6914 dpurdie 2461
                    );
7176 dpurdie 2462
 
2463
            stmt.setString(1, mHostname);
2464
            stmt.setString(2, rconIdList);
6914 dpurdie 2465
 
2466
            ResultSet rset = stmt.executeQuery();
2467
 
2468
            while (rset.next()) {
2469
                Integer ii = rset.getInt("rcon_id");
2470
                rv.add(ii);
2471
            }
2472
 
2473
            rset.close();
2474
            stmt.close();
2475
        }
2476
        catch ( SQLException e )
2477
        {
2478
            handleSQLException(e, "");
2479
        }
2480
        finally
2481
        {
2482
            // this block is executed regardless of what happens in the try block
2483
            // even if an exception is thrown
2484
            // ensure disconnect
2485
            disconnect();
2486
        }
2487
        return rv;
2488
    }
2489
 
7044 dpurdie 2490
    /**
7088 dpurdie 2491
     * Extract all package-version information for released packages
2492
     * Used in both Escrow and non-Escrow modes
7044 dpurdie 2493
     * 
2494
     * @param   rippleEngine        - Instance to use
2495
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2496
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
6914 dpurdie 2497
     *  
2498
     * Overridden in ReleaseManagerUtf
2499
     *  
2500
     */
7044 dpurdie 2501
    protected void queryPackageVersions(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
6914 dpurdie 2502
    {
2503
        Phase phase = new Phase("rmData");
7044 dpurdie 2504
        mLogger.debug("queryPackageVersions {}", mDaemon);
7137 dpurdie 2505
 
6914 dpurdie 2506
        try
2507
        {
2508
            if (mDaemon)
2509
            {
7082 dpurdie 2510
                // Get package information on ALL released packages within the release of interest
6914 dpurdie 2511
                //
2512
                mLogger.debug("queryPackageVersions: stmt8");
2513
                phase.setPhase("getAllPkgs1");
2514
                PreparedStatement stmt8 = mConnection.prepareStatement(
2515
                        "SELECT rc.pv_id," +
7046 dpurdie 2516
                                " p.pkg_id," +
2517
                                " p.pkg_name," +
2518
                                " pv.pkg_version," +
2519
                                " pv.v_ext," +
2520
                                " pv.ripple_field," +
2521
                                " pv.major_limit," +
2522
                                " pv.minor_limit," +
2523
                                " pv.patch_limit," +
2524
                                " pv.build_number_limit," +
2525
                                " pv.build_type," +
2526
                                " rc.sdktag_id," +
2527
                                " rc.ripple_stop," +
2528
                                " peg.pv_id as pegged," +
2529
                                " release_manager.PK_RMAPI.return_vcs_tag(rc.pv_id) AS vcsTag," +
2530
                                " pv.build_time" +
6914 dpurdie 2531
                                " FROM release_manager.release_content rc," +
2532
                                "  release_manager.package_versions pv," +
2533
                                "  release_manager.packages p," +
2534
                                "  release_manager.pegged_versions peg" +
7176 dpurdie 2535
                                " WHERE rc.rtag_id=?" +
6914 dpurdie 2536
                                " AND pv.pv_id    = rc.pv_id" +
2537
                                " AND p.pkg_id    = pv.pkg_id" +
2538
                                " AND peg.rtag_id(+) = rc.rtag_id" +
2539
                                " AND peg.pv_id(+) = rc.pv_id" +
2540
                                " ORDER BY rc.pv_id"
2541
                        );
7176 dpurdie 2542
                stmt8.setInt(1, baseline);
6914 dpurdie 2543
                mLogger.debug("queryPackageVersions: stmt8 Prepared");
2544
                stmt8.setFetchSize(1000);
7023 dpurdie 2545
                RmResultSet rset8 = new RmResultSet(stmt8.executeQuery(), "queryPackageVersions rset8");
6914 dpurdie 2546
                mLogger.debug("queryPackageVersions: stmt8 Query Done");
2547
 
2548
                while( rset8.next() )
2549
                {
7023 dpurdie 2550
                    int pv_id = rset8.mustGetKeyInt("pv_id");
2551
                    int pkg_id = rset8.mustGetInt("pkg_id");
2552
                    String pkg_name = rset8.mustGetString("pkg_name");
2553
                    String pkg_version = rset8.mustGetString("pkg_version");
2554
                    String v_ext = rset8.getString("v_ext", "");
2555
                    String ripple_field = rset8.getString("ripple_field", "b");
2556
                    int major_limit = rset8.getInt("major_limit",0);
2557
                    int minor_limit = rset8.getInt("minor_limit", 0);
2558
                    int patch_limit = rset8.getInt("patch_limit",0);
2559
                    int build_number_limit = rset8.getInt("build_number_limit", 0);
2560
                    String vcs_tag = rset8.getString("vcsTag","");
2561
                    int isAnSdk = rset8.getInt("sdktag_id",0); 
2562
                    int isPegged = rset8.getInt("pegged",0);
2563
                    String buildType = rset8.getString("build_type", null);
6914 dpurdie 2564
                    boolean isBuildable = ( buildType != null ) && (buildType.equals("A") || buildType.equals("Y") );
7046 dpurdie 2565
                    int buildTime = rset8.getInt("build_time", 60);
6914 dpurdie 2566
 
7023 dpurdie 2567
                    String rippleStopData = rset8.getString("ripple_stop","n");
2568
                    char rippleStop = rippleStopData.charAt(0);
6914 dpurdie 2569
 
2570
                    Package p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
2571
                    p.mMajorLimit = major_limit;
2572
                    p.mMinorLimit = minor_limit;
2573
                    p.mPatchLimit = patch_limit;
2574
                    p.mBuildLimit = build_number_limit;
2575
                    p.mIsSdk = isAnSdk > 0;
2576
                    p.mIsPegged = isPegged > 0;
2577
                    p.mIsBuildable = isBuildable;
2578
                    p.mRippleStop = rippleStop;
7046 dpurdie 2579
                    p.mBuildTime = buildTime;
6914 dpurdie 2580
 
2581
                    //  If this package is to be replaced by a planned package then
2582
                    //  insert some of the current packages attributes
2583
                    //  Otherwise, add the the package to the package collection
7163 dpurdie 2584
                    //  TODO - Not sure this code is in use anymore
7082 dpurdie 2585
 
6914 dpurdie 2586
                    Package plannedPackage = findPackage(p.mAlias, packageCollection);
2587
                    if ( plannedPackage == NULL_PACKAGE )
2588
                    {
7176 dpurdie 2589
                        mLogger.debug("queryPackageVersions rset8 no planned package {}", pv_id);
6914 dpurdie 2590
                        packageCollection.add(p);
2591
                    }
2592
                    else
2593
                    {
2594
                        //  Copy these flags from the package that will be replaced
2595
                        //      Should not be able to replace a package provided by an SDK
2596
                        plannedPackage.mIsSdk = p.mIsSdk;
2597
 
2598
                        // A pegged package can be replaced with a directly built package
2599
                        // plannedPackage.mIsPegged = p.mIsPegged;
2600
                    }
2601
                }
2602
 
2603
                mLogger.debug("queryPackageVersions: stmt8 processing complete");
2604
                rset8.close();
2605
                stmt8.close();
2606
 
2607
                // get released package dependency info
2608
                // 
2609
                mLogger.debug("queryPackageVersions: stmt9");
2610
                phase.setPhase("getAllPkgs2");
2611
                PreparedStatement stmt9 = mConnection.prepareStatement(
7023 dpurdie 2612
                        "select rc.pv_id as pv_id, dpv.pv_id as dpv_id, p.pkg_name, dpv.v_ext" +
6914 dpurdie 2613
                                " from release_manager.release_content rc," +
2614
                                "      release_manager.package_versions pv," + 
2615
                                "      release_manager.package_dependencies pd,"+
2616
                                "      release_manager.package_versions dpv,"+
2617
                                "      release_manager.packages p" +
7176 dpurdie 2618
                                " where rc.rtag_id=?" + 
6914 dpurdie 2619
                                "  and pv.pv_id = rc.pv_id" +
2620
                                "  and pd.pv_id=pv.pv_id" +
2621
                                "  and dpv.pv_id=pd.dpv_id" +
2622
                                "  and p.pkg_id=dpv.pkg_id" +
2623
                                " order by rc.pv_id"
2624
                        );
2625
                mLogger.debug("queryPackageVersions: stmt9 prepared");
7176 dpurdie 2626
                stmt9.setInt(1, baseline);
6914 dpurdie 2627
                stmt9.setFetchSize(1000);
7023 dpurdie 2628
                RmResultSet rset9 = new RmResultSet(stmt9.executeQuery(), "queryPackageVersions rset9");
6914 dpurdie 2629
                mLogger.debug("queryPackageVersions: stmt9 query done");
2630
 
2631
                while( rset9.next() )
2632
                {
7023 dpurdie 2633
                    int pv_id = rset9.mustGetKeyInt("pv_id");
2634
                    int dpv_id = rset9.mustGetInt("dpv_id");
2635
                    String pkg_name = rset9.mustGetString("pkg_name");
2636
                    String v_ext = rset9.getString("v_ext","");
6914 dpurdie 2637
 
7082 dpurdie 2638
                    Package p = findPackage(pv_id, packageCollection);
2639
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2640
                    {
7163 dpurdie 2641
                        p.addDependency(pkg_name + v_ext, dpv_id );
6914 dpurdie 2642
                    }
7082 dpurdie 2643
 
6914 dpurdie 2644
                }
2645
                mLogger.debug("queryPackageVersions: stmt9 processing complete");
2646
 
2647
                rset9.close();
2648
                stmt9.close();
2649
 
2650
                // get released package build info
2651
                mLogger.debug("queryPackageVersions: stmt10");
2652
                phase.setPhase("getAllPkgs3");
2653
                PreparedStatement stmt10 = mConnection.prepareStatement(
2654
                        "select rc.pv_id, bm.bm_name, bsa.bsa_name " +
2655
                                "from release_manager.release_content rc," +
2656
                                "     release_manager.package_versions pv," +
2657
                                "     release_manager.package_build_info pbi," +
2658
                                "     release_manager.build_machines bm," +
2659
                                "     release_manager.build_standards_addendum bsa " +
2660
                                "where rc.rtag_id=?" + 
2661
                                "     and pv.pv_id = rc.pv_id" +
2662
                                "     and pbi.pv_id=pv.pv_id" +
2663
                                "     and bm.bm_id=pbi.bm_id" +
2664
                                "     and bsa.bsa_id=pbi.bsa_id " +
2665
                                "order by rc.pv_id"
2666
                        );
2667
                stmt10.setFetchSize(1000);
2668
                stmt10.setInt(1, baseline);
7023 dpurdie 2669
                RmResultSet rset10 = new RmResultSet(stmt10.executeQuery(), "queryPackageVersions rset10");
6914 dpurdie 2670
 
2671
                while( rset10.next() )
2672
                {
7023 dpurdie 2673
                    int pv_id = rset10.mustGetKeyInt("pv_id");
2674
                    String bm_name = rset10.mustGetString("bm_name");
2675
                    String bsa_name = rset10.mustGetString("bsa_name");
6914 dpurdie 2676
 
7082 dpurdie 2677
                    Package p = findPackage(pv_id, packageCollection);
2678
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2679
                    {
2680
                        BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
2681
                        if ( bs.supportedBuildStandard() )
2682
                        {
2683
                            p.mBuildStandardCollection.add(bs);
2684
                        }
2685
                    }
2686
                }
2687
 
2688
                rset10.close();
2689
                stmt10.close();
2690
 
2691
                // get released package unit test info
2692
                mLogger.debug("queryPackageVersions: stmt11");
2693
                phase.setPhase("getAllPkgs4");
2694
                PreparedStatement stmt11 = mConnection.prepareStatement(
2695
                        "select rc.pv_id, tt.test_type_name " +
2696
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.unit_tests ut, release_manager.test_types tt " +
7176 dpurdie 2697
                                "where rc.rtag_id=?" +
6914 dpurdie 2698
                                " and pv.pv_id = rc.pv_id and ut.pv_id=pv.pv_id and tt.test_type_id=ut.test_types_fk " +
2699
                                "order by rc.pv_id"
2700
                        );
7176 dpurdie 2701
                stmt11.setInt(1, baseline);
6914 dpurdie 2702
                stmt11.setFetchSize(1000);
7023 dpurdie 2703
                RmResultSet rset11 = new RmResultSet(stmt11.executeQuery(), "queryPackageVersions rset11");
6914 dpurdie 2704
 
2705
                while( rset11.next() )
2706
                {
7023 dpurdie 2707
                    int pv_id = rset11.mustGetKeyInt("pv_id");
7082 dpurdie 2708
                    String test_type_name = rset11.mustGetString("test_type_name");
6914 dpurdie 2709
                    Package p = findPackage(pv_id, packageCollection);
7082 dpurdie 2710
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2711
                    {
2712
                        if ( test_type_name.compareTo("Autobuild UTF") == 0 )
2713
                        {
2714
                            p.mHasAutomatedUnitTests = true;
2715
                        }
2716
                    }
2717
                }
2718
 
2719
                rset11.close();
2720
                stmt11.close();
2721
 
2722
                // get released package build failure info...
2723
                // view based
2724
                mLogger.debug("queryPackageVersions: stmt12");
2725
                phase.setPhase("getAllPkgs5");
2726
                PreparedStatement stmt12 = mConnection.prepareStatement(
2727
                        "SELECT rc.pv_id," +
2728
                        "  u.user_email" +
2729
                        " FROM release_manager.release_content rc," +
2730
                        "  release_manager.release_tags rt," +
2731
                        "  release_manager.package_versions pv," +
2732
                        "  release_manager.autobuild_failure af," +
2733
                        "  release_manager.members_group mg," +
2734
                        "  release_manager.users u" +
7176 dpurdie 2735
                        " WHERE rc.rtag_id     = ?" +
6914 dpurdie 2736
                        " AND rt.rtag_id       = rc.rtag_id" +
2737
                        " AND pv.pv_id         = rc.pv_id" +
2738
                        " AND af.view_id       = rc.base_view_id" +
2739
                        " AND mg.group_email_id= af.group_email_id" +
2740
                        " AND u.user_id        = mg.user_id" +
2741
                        " AND af.proj_id       = rt.proj_id" +
2742
                        " ORDER BY rc.pv_id"
2743
                        );
7176 dpurdie 2744
                stmt12.setInt(1, baseline);
6914 dpurdie 2745
                stmt12.setFetchSize(1000);
7023 dpurdie 2746
                RmResultSet rset12 = new RmResultSet(stmt12.executeQuery(), "queryPackageVersions rset12");
6914 dpurdie 2747
 
2748
                while( rset12.next() )
2749
                {
7023 dpurdie 2750
                    int pv_id = rset12.mustGetKeyInt("pv_id");
7082 dpurdie 2751
                    String user_email = rset12.getString("user_email",null);
6914 dpurdie 2752
                    Package p = findPackage(pv_id, packageCollection);
2753
 
7082 dpurdie 2754
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2755
                    {
7088 dpurdie 2756
                        p.addEmail(user_email);
6914 dpurdie 2757
                    }
2758
                }
2759
 
2760
                rset12.close();
2761
                stmt12.close();
2762
 
2763
                // get released advisory ripple info
2764
                mLogger.debug("queryPackageVersions: stmt14");
2765
                phase.setPhase("getAllPkgs6");
2766
                PreparedStatement stmt14 = mConnection.prepareStatement(
2767
                        "select rc.pv_id " +
2768
                                "from release_manager.release_content rc, release_manager.package_versions pv, release_manager.advisory_ripple ar " +
7176 dpurdie 2769
                                "where rc.rtag_id=?" +
6914 dpurdie 2770
                                " and pv.pv_id = rc.pv_id and ar.rtag_id=rc.rtag_id and ar.pv_id=rc.pv_id " +
2771
                                "order by rc.pv_id"
2772
                        );
2773
                stmt14.setFetchSize(1000);
7176 dpurdie 2774
                stmt14.setInt(1, baseline);
7023 dpurdie 2775
                RmResultSet rset14 = new RmResultSet(stmt14.executeQuery(), "queryPackageVersions rset14");
6914 dpurdie 2776
 
2777
                while( rset14.next() )
2778
                {
7023 dpurdie 2779
                    int pv_id = rset14.mustGetInt("pv_id");
6914 dpurdie 2780
                    Package p = findPackage(pv_id, packageCollection);
7082 dpurdie 2781
                    if ( p != NULL_PACKAGE )
6914 dpurdie 2782
                    {
2783
                        p.mAdvisoryRipple = true;
2784
                    }
2785
                }
2786
 
2787
                rset14.close();
2788
                stmt14.close();
7023 dpurdie 2789
 
6914 dpurdie 2790
            }
2791
            else
2792
            {
2793
                // Escrow Mode
2794
                // get released product info
2795
                mLogger.debug("queryPackageVersions: stmt18");
2796
                PreparedStatement stmt = mConnection.prepareStatement(
2797
                        "select oc.prod_id, p.pkg_name, pv.pkg_version, pv.v_ext," +
2798
                                "release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag" +
2799
                                " from deployment_manager.bom_contents bc," +
2800
                                "deployment_manager.operating_systems os," +
2801
                                "deployment_manager.os_contents oc," +
2802
                                "release_manager.package_versions pv," +
2803
                                "release_manager.packages p" +
7176 dpurdie 2804
                                " where bc.bom_id=?" +
6914 dpurdie 2805
                                " and os.node_id=bc.node_id" +
2806
                                " and oc.os_id=os.os_id" +
2807
                                " and pv.pv_id=oc.prod_id" +
2808
                                " and p.pkg_id=pv.pkg_id" +
2809
                                " order by oc.prod_id"
2810
                        );
2811
                stmt.setFetchSize(1000);
7176 dpurdie 2812
                stmt.setInt(1, baseline);
7023 dpurdie 2813
                RmResultSet rset = new RmResultSet(stmt.executeQuery(), "queryPackageVersions rset");
6914 dpurdie 2814
 
2815
                while( rset.next() )
2816
                {
7023 dpurdie 2817
                    int pv_id = rset.mustGetKeyInt("prod_id");
2818
                    String pkg_name = rset.mustGetString("pkg_name");
2819
                    String pkg_version = rset.mustGetString("pkg_version");
2820
                    String v_ext = rset.getString("v_ext", "");
2821
                    String vcs_tag = rset.getString("vcsTag","");
2822
 
6914 dpurdie 2823
                    Package p = findPackage(pv_id, packageCollection);
2824
                    if ( p == NULL_PACKAGE )
2825
                    {
2826
                        Package q = new Package(0, pv_id, pkg_name, pkg_version, v_ext, pkg_name + "." + pkg_version, vcs_tag, 'x');
2827
                        packageCollection.add(q);
2828
                    }
2829
                }
2830
 
2831
                rset.close();
2832
                stmt.close();
7044 dpurdie 2833
 
2834
                //  Now have all the package-versions used in the SBOM need to 
2835
                //      determine all the dependent packages 
2836
                //      determine the build info for all the packages
2837
 
2838
                //  Determine all dependent packages
2839
                //  Note: use a ListIterator as it allows traverseDependencies to modify the packageCollection
2840
                for (ListIterator<Package> it = packageCollection.listIterator(); it.hasNext(); )
2841
                {
2842
                    Package p = it.next();
2843
                    traverseDependencies(packageCollection, p, false, it);
2844
                }
2845
 
2846
                //  Add required build information
2847
                for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
2848
                {
2849
                    Package p = it.next();
2850
                    queryBuildInfo(rippleEngine, p);
2851
                }
6914 dpurdie 2852
            }
2853
        }
2854
        catch ( SQLException e )
2855
        {
2856
            handleSQLException(e, "");
2857
        }
7088 dpurdie 2858
        phase.setPhase("End");
2859
    }
2860
 
2861
    /**
2862
     * Extract all package-version information for Planned Packages (WIPS)
2863
     * Not used in ESCROW
2864
     * 
2865
     * @param   rippleEngine        - Instance to use
2866
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2867
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
2868
     *  
2869
     * Overridden in ReleaseManagerUtf
2870
     *  
2871
     */
2872
    protected void queryWips(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
2873
    {
2874
        if (!mDaemon){
2875
            return;
2876
        }
2877
 
2878
        Phase phase = new Phase("rmData");
2879
        mLogger.debug("queryWips {}", mDaemon);
2880
 
2881
        try
2882
        {
2883
            // Get planned package info
2884
            // Support multiple WIPS on the same package and build in the order they were released
2885
            // These are packages that are marked as pending build
2886
            //
2887
            mLogger.debug("queryPackageVersions: stmt1");
2888
            phase.setPhase("getPlannedPkgs1");
2889
            PreparedStatement stmt1 = mConnection.prepareStatement(
2890
                    "select pl.pv_id, pv.modified_stamp" +
2891
                            " from release_manager.planned pl," +
2892
                            "      release_manager.package_versions pv," +
2893
                            "      release_manager.packages p" +
7176 dpurdie 2894
                            " where pl.rtag_id=?" +
7088 dpurdie 2895
                            "   and pv.build_type='A' and pv.dlocked='A'" +
2896
                            "   and pv.pv_id=pl.pv_id and p.pkg_id=pv.pkg_id" +
2897
                            " order by pv.modified_stamp"
2898
                    );
2899
            stmt1.setFetchSize(500);
7176 dpurdie 2900
            stmt1.setInt(1, baseline);
7088 dpurdie 2901
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "queryPackageVersions rset1");
2902
 
2903
            while( rset1.next() )
2904
            {
2905
                int pvId = rset1.mustGetKeyInt("pv_id");
2906
 
7099 dpurdie 2907
                Package p = getPackageInfo(pvId, rippleEngine, true);
7088 dpurdie 2908
                if ( p != NULL_PACKAGE)
2909
                {
2910
                    p.mIsNotReleased = true;
2911
                    p.mDirectlyPlanned = true;
2912
                    p.mBuildReason = BuildReason.NewVersion;
2913
 
2914
                    // If there are multiple packages with the same Alias, then only the first one
2915
                    // will be placed in the build set. The will be the oldest, the first one released
2916
                    // to be built
2917
 
2918
                    Package prevPlannedPackage = findPackage(p.mAlias, packageCollection);
2919
                    if ( prevPlannedPackage == NULL_PACKAGE )
2920
                    {
7176 dpurdie 2921
                        mLogger.debug("queryWips rset1 no previous WIP package {}", pvId);
7088 dpurdie 2922
                        packageCollection.add(p);
2923
                    }
2924
                }
2925
            }
2926
 
2927
            rset1.close();
2928
            stmt1.close();
2929
 
2930
            //  Process Scheduled Build Approvals. OpCode is 2
2931
            //      These are treated as requests to not-include a 'Pending' package-version in the current build set
2932
            //      If there is an un-expired instruction, then remove the pending package-version from the build set
2933
            //
2934
            //  Process all expired requests
2935
            //      These are scheduled builds were the scheduled time has been exceeded
2936
            //      Simply discard the instruction and let the Approved build proceed
2937
            //
2938
            DaemonInstruction di = new DaemonInstruction(baseline, 2, true);
2939
 
2940
            phase.setPhase("removeOldSchedBuilds");
2941
            while ( getDaemonInst( di ) )
2942
            {
2943
                markDaemonInstCompleted(di.instruction);
2944
                mLogger.info("queryPackageVersions remove Scheduled Build Approvals {}", di.pvId);
2945
            }
2946
 
2947
            phase.setPhase("getSchedBuilds");
2948
            di = new DaemonInstruction(baseline, 2, false);
2949
            while ( getDaemonInst( di ) )
2950
            {
2951
                Package p = findPackage(di.pvId, packageCollection);
2952
 
2953
                if ( p != NULL_PACKAGE )
2954
                {
2955
                    mLogger.info("queryPackageVersions Scheduled Build Approvals {}", di.pvId);
2956
                    packageCollection.remove(p);
2957
                }
2958
                else
2959
                {
2960
                    // discard - the package no longer exists
2961
                    markDaemonInstCompleted( di.instruction );
2962
                    mLogger.info("queryPackageVersions remove Scheduled Build Approvals for nonexistent package {}", di.pvId);
2963
                }
2964
            }                
2965
 
2966
        }
7082 dpurdie 2967
        catch ( SQLException e )
2968
        {
2969
            handleSQLException(e, "");
2970
        }
6914 dpurdie 2971
        phase.setPhase("End");
2972
    }
2973
 
7082 dpurdie 2974
    /**
2975
     * Extract all TEST package-version information
2976
     * Only active in Daemon Mode
2977
     * 
2978
     * @param   rippleEngine        - Instance to use
2979
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
2980
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
2981
     *  
2982
     * Overridden in ReleaseManagerUtf
2983
     *  
2984
     */
2985
    protected void queryTest(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
2986
    {
2987
        if (!mDaemon){
2988
            return;
2989
        }
2990
 
2991
        Phase phase = new Phase("rmData");
2992
        mLogger.debug("queryTest {}", mDaemon);
2993
 
2994
        try
2995
        {
2996
 
2997
            // Daemon Instruction: Test Build Package
2998
            //  An op code of 1 means test build
2999
            //
3000
            // Trust nothing - these are mostly wips that at any time may have:
3001
            // - no build location
3002
            // - no build label
3003
            // - an empty build standard collection
3004
            // proceed with defaults above if necessary (the build will subsequently fail)
3005
            // in all cases, build a meaningful email body to inform the user
3006
            // of the snapshot of build information that applied to the build and store in:
3007
            // - mTestBuildEmailBody
3008
 
3009
            mLogger.debug("queryTest: stmt141");
3010
            phase.setPhase("getTestBuild1");
3011
            DaemonInstruction di = new DaemonInstruction( baseline, 1, true);
3012
            while ( getDaemonInst( di ) )
3013
            {
7176 dpurdie 3014
                mLogger.debug("queryPackageVersions test build data {}", di.pvId);
7082 dpurdie 3015
 
7099 dpurdie 3016
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7082 dpurdie 3017
                if ( p == NULL_PACKAGE )
3018
                {
3019
                    mLogger.error("queryTest rset15 no data found {}", di.instruction);
3020
                    markDaemonInstCompleted( di.instruction );
3021
 
3022
                }
3023
                else
3024
                {
3025
                    packageCollection.add(p);
3026
 
3027
                    //  Set some Test information
3028
                    //  Avoid interaction with real versions
3029
                    //  Flag as not pegged - so that we test build
3030
                    p.mVersion = "0.0.0000";
3031
                    p.mTestBuildInstruction = di.instruction;
3032
                    p.addEmail(di.userEmail);
3033
                    p.mBuildReason = BuildReason.Test;
3034
                    p.mIsPegged = false;
3035
                    p.mIsNotReleased = true;
3036
                }
3037
            }
3038
        }
3039
        catch ( SQLException e )
3040
        {
3041
            handleSQLException(e, "");
3042
        }
3043
        phase.setPhase("End");
3044
    }
6914 dpurdie 3045
 
7082 dpurdie 3046
    /**
3047
     * Extract all Ripple Request package-version information
3048
     * The returned list is in daemon instruction id order - ie the first request will be first
3049
     * Only active in Daemon Mode
3050
     * 
3051
     * @param   rippleEngine        - Instance to use
3052
     * @param   packageCollection   - Package Collection structure to fill. Expected to be cleared
3053
     * @param   baseline            - RtagId of the release being processed, BomId of an Escrow being processed
3054
     *  
3055
     * Overridden in ReleaseManagerUtf
3056
     *  
3057
     */
3058
    protected void queryRipples(RippleEngine rippleEngine, ArrayList<Package> packageCollection, int baseline) throws SQLException, Exception
3059
    {
3060
        if (!mDaemon){
3061
            return;
3062
        }
3063
 
3064
        Phase phase = new Phase("rmData");
3065
        mLogger.debug("queryPackageVersions {}", mDaemon);
3066
 
3067
        try
3068
        {
3069
            // Daemon Instruction: Force Package Ripple
3070
            //  An op code of 0 means force ripple
3071
 
3072
            phase.setPhase("getDaemonInstructions1");
3073
            DaemonInstruction di = new DaemonInstruction( baseline, 0, true);
3074
            while ( getDaemonInst( di ) )
3075
            {
7099 dpurdie 3076
                Package p = getPackageInfo(di.pvId, rippleEngine, false);
7082 dpurdie 3077
                if ( p != NULL_PACKAGE )
3078
                {
7176 dpurdie 3079
                    mLogger.debug("queryPackageVersions forced ripple data {}", di.pvId);
7082 dpurdie 3080
                    packageCollection.add(p);
3081
                    p.mForcedRippleInstruction = di.instruction;
3082
                    p.addEmail(di.userEmail);
7099 dpurdie 3083
                    p.mBuildReason = BuildReason.Forced;
7082 dpurdie 3084
                    p.mIsNotReleased = true;
3085
                }
3086
                else
3087
                {
3088
                    // discard
3089
                    markDaemonInstCompleted( di.instruction );
3090
                }
3091
            }
3092
 
3093
        }
3094
        catch ( SQLException e )
3095
        {
3096
            handleSQLException(e, "");
3097
        }
3098
        phase.setPhase("End");
3099
    }
3100
 
3101
    /** Get all build information for a single package
3102
     *  Don't use this where lots of packages are expected, but should be OK to get data for TEST, WIP and Ripples
3103
     *  
3104
     *  Does not get:
3105
     *      mBuildReason
3106
     *      mDirectlyPlanned
3107
     *  
3108
     *  @param  pvId    - Package to process
3109
     * @param rippleEngine - Ripple engine associated wit the Release
7099 dpurdie 3110
     * @param useChangeType - true: For a WIP, the change type is significant
7082 dpurdie 3111
     * @throws Exception 
3112
     *  
3113
     *  @returns a package - May be null, but this is not good
3114
     */
7099 dpurdie 3115
    Package getPackageInfo(int pvId, RippleEngine rippleEngine, boolean useChangeType) throws Exception
7082 dpurdie 3116
    {
3117
        Package p = NULL_PACKAGE;
3118
 
3119
        try
3120
        {
3121
            // Get Package info
3122
            //
3123
            mLogger.debug("getPackageInfo: stmt1");
3124
            PreparedStatement stmt1 = mConnection.prepareStatement(
3125
                    "select pv.pv_id, p.pkg_id, p.pkg_name, pv.pkg_version, " +
3126
                            " pv.v_ext, pv.change_type, pv.ripple_field," +
3127
                            " pv.major_limit, pv.minor_limit, pv.patch_limit, pv.build_number_limit," +
3128
                            " pv.modified_stamp," +
3129
                            " release_manager.PK_RMAPI.return_vcs_tag(pv.pv_id) AS vcsTag," +
3130
                            " pv.build_time" +
3131
                            " from " +
3132
                            "      release_manager.package_versions pv," +
3133
                            "      release_manager.packages p" +
7176 dpurdie 3134
                            " where pv.pv_id=?" +
7082 dpurdie 3135
                            "   and p.pkg_id=pv.pkg_id"
3136
 
3137
                    );
7176 dpurdie 3138
            stmt1.setInt(1, pvId);
7082 dpurdie 3139
            stmt1.setFetchSize(500);
3140
            RmResultSet rset1 = new RmResultSet(stmt1.executeQuery(), "getPackageInfo rset1");
3141
 
3142
            //  Package must exist
3143
            if ( ! rset1.next() )
3144
            {
3145
                return NULL_PACKAGE;
3146
            }
3147
 
3148
 
3149
            int pv_id = rset1.mustGetKeyInt("pv_id");
3150
            int pkg_id = rset1.mustGetInt("pkg_id");
3151
            String pkg_name = rset1.mustGetString("pkg_name");
3152
            String pkg_version = rset1.mustGetString("pkg_version");
3153
            int buildTime = rset1.getInt("build_time", 60);
3154
 
3155
            // Previous Version of this package, without the project suffix
3156
            String pkg_prevVersion = getBaseVersionNumber(pv_id);
3157
            if ( pkg_prevVersion == null)
3158
            {
3159
                // show stopper
3160
                mLogger.error("getPackageInfo. No Previous version {}", pv_id);
3161
                throw new Exception("getPackageInfo. No Previous version" + pv_id);
3162
            }
3163
 
3164
            String v_ext = rset1.getString("v_ext","");
3165
            String change_type = rset1.getString("change_type", "P");
3166
 
3167
            char ct = 'P';
3168
 
3169
            if ( change_type.compareTo("M") == 0 )
3170
            {
3171
                ct = 'M';
3172
            }
3173
            else if ( change_type.compareTo("N") == 0 )
3174
            {
3175
                ct = 'N';
3176
            }
3177
            else if ( change_type.compareTo("P") == 0 )
3178
            {
3179
                ct = 'P';
3180
            }
3181
            else if ( change_type.compareTo("F") == 0 )
3182
            {
3183
                ct = 'F';
3184
            }
3185
 
3186
            String ripple_field = rset1.getString("ripple_field", "b");
3187
            int major_limit = rset1.getInt("major_limit", 0);
3188
            int minor_limit = rset1.getInt("minor_limit",0);
3189
            int patch_limit = rset1.getInt("patch_limit",0);
3190
            int build_number_limit = rset1.getInt("build_number_limit",0);
3191
            String vcs_tag = rset1.getString("vcsTag", "");
7099 dpurdie 3192
 
3193
            if ( useChangeType ) {
7169 dpurdie 3194
                //  WIP - Change type is significant
3195
                //        The next version number will be based on the previous version number of the package
3196
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0), ct);
3197
                p.mPrevVersion = pkg_prevVersion;
3198
 
7099 dpurdie 3199
            } else {
7169 dpurdie 3200
                //  RIPPLE/TEST - Change type is not significant
3201
                //                Next version number will will be based on the current version number
7099 dpurdie 3202
                p = new Package(pkg_id, pv_id, pkg_name, pkg_version, v_ext, pkg_name + v_ext, vcs_tag, ripple_field.charAt(0));
3203
            }
7082 dpurdie 3204
            p.mMajorLimit = major_limit;
3205
            p.mMinorLimit = minor_limit;
3206
            p.mPatchLimit = patch_limit;
3207
            p.mBuildLimit = build_number_limit;
3208
            p.mBuildTime = buildTime;
3209
 
3210
            rset1.close();
3211
            stmt1.close();
3212
 
3213
            // get Package dependency info
3214
            mLogger.debug("getPackageInfo: stmt2");
3215
            PreparedStatement stmt2 = mConnection.prepareStatement(
7099 dpurdie 3216
                    "select p.pkg_name, dpv.v_ext, dpv.pv_id" +
7082 dpurdie 3217
                            " from " +
3218
                            "     release_manager.package_versions pv,"+
3219
                            "     release_manager.package_dependencies pd," +
7099 dpurdie 3220
                            "     release_manager.package_versions dpv,"+
3221
                            "     release_manager.packages p" +
7176 dpurdie 3222
                            " where pv.pv_id=?" + 
7082 dpurdie 3223
                            "  and pd.pv_id=pv.pv_id"+
7099 dpurdie 3224
                            "  and dpv.pv_id=pd.dpv_id" +
3225
                            "  and pd.dpkg_id = p.pkg_id"
7082 dpurdie 3226
                    );
3227
            stmt2.setFetchSize(500);
7176 dpurdie 3228
            stmt2.setInt(1, pvId);
7082 dpurdie 3229
            RmResultSet rset2 = new RmResultSet(stmt2.executeQuery(), "getPackageInfo rset2");
3230
 
3231
            while ( rset2.next() )
3232
            {
7099 dpurdie 3233
                String dpv_name = rset2.mustGetKeyString("pkg_name");
7114 dpurdie 3234
                String dpv_ext = rset2.getString("v_ext","");
7082 dpurdie 3235
                int    dpvId = rset2.mustGetInt("pv_id");
3236
 
7163 dpurdie 3237
                p.addDependency(dpv_name + dpv_ext, dpvId);
7082 dpurdie 3238
            }
3239
 
3240
            rset2.close();
3241
            stmt2.close();
3242
 
3243
            // get Package build info
3244
            mLogger.debug("getPackageInfo: stmt3");
3245
            PreparedStatement stmt3 = mConnection.prepareStatement(
3246
                    "select bm.bm_name, bsa.bsa_name" +
3247
                            " from " +
3248
                            "   release_manager.package_versions pv," +
3249
                            "   release_manager.package_build_info pbi," +
3250
                            "   release_manager.build_machines bm," +
3251
                            "   release_manager.build_standards_addendum bsa " +
7176 dpurdie 3252
                            " where pv.pv_id=?" + 
7082 dpurdie 3253
                            "   and pbi.pv_id=pv.pv_id" +
3254
                            "   and bm.bm_id=pbi.bm_id" +
3255
                            "   and bsa.bsa_id=pbi.bsa_id "
3256
                    );
3257
            stmt3.setFetchSize(500);
7176 dpurdie 3258
            stmt3.setInt(1, pvId);
7082 dpurdie 3259
            RmResultSet rset3 = new RmResultSet(stmt3.executeQuery(), "getPackageInfo rset3");
3260
 
3261
            while ( rset3.next() )
3262
            {
3263
                String bm_name = rset3.mustGetString("bm_name");
3264
                String bsa_name = rset3.mustGetString("bsa_name");
3265
 
3266
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3267
                if ( bs.supportedBuildStandard() )
3268
                {
3269
                    p.mBuildStandardCollection.add(bs);
3270
                }
3271
            }
3272
 
3273
            rset3.close();
3274
            stmt3.close();
3275
 
3276
            // get Package unit test info
3277
            mLogger.debug("getPackageInfo: stmt4");
3278
            PreparedStatement stmt4 = mConnection.prepareStatement(
3279
                    "select pv.pv_id, tt.test_type_name" +
3280
                    "  from "+
3281
                    "       release_manager.package_versions pv,"+
3282
                    "       release_manager.unit_tests ut," +
3283
                    "       release_manager.test_types tt" +
7176 dpurdie 3284
                    " where pv.pv_id=?" + 
7082 dpurdie 3285
                    "  and ut.pv_id=pv.pv_id" +
3286
                    "  and tt.test_type_id=ut.test_types_fk"
3287
                    );
3288
            stmt4.setFetchSize(500);
7176 dpurdie 3289
            stmt4.setInt(1, pvId);
7082 dpurdie 3290
            RmResultSet rset4 = new RmResultSet(stmt4.executeQuery(), "getPackageInfo rset4");
3291
 
3292
            while ( rset4.next() )
3293
            {
3294
                String test_type_name = rset4.mustGetString("test_type_name");
3295
                if ( test_type_name.compareTo("Autobuild UTF") == 0 )
3296
                {
3297
                    p.mHasAutomatedUnitTests = true;
3298
                }
3299
            }
3300
 
3301
            rset4.close();
3302
            stmt4.close();
3303
 
3304
            // get Package build failure info...
3305
            //      view based
3306
            mLogger.debug("getPackageInfo: stmt5");
3307
            PreparedStatement stmt5 = mConnection.prepareStatement(
3308
                    "SELECT rc.pv_id," +
3309
                            "  u.user_email" +
3310
                            " FROM release_manager.release_content rc," +
3311
                            "  release_manager.release_tags rt," +
3312
                            "  release_manager.package_versions pv," +
3313
                            "  release_manager.autobuild_failure af," +
3314
                            "  release_manager.members_group mg," +
3315
                            "  release_manager.users u" +
7176 dpurdie 3316
                            " WHERE rc.rtag_id     = ?" +
7082 dpurdie 3317
                            " AND rt.rtag_id       = rc.rtag_id" +
7176 dpurdie 3318
                            " AND pv.pv_id         =?" +
7082 dpurdie 3319
                            " AND pv.pv_id         = rc.pv_id" +
3320
                            " AND af.view_id       = rc.base_view_id" +
3321
                            " AND mg.group_email_id= af.group_email_id" +
3322
                            " AND u.user_id        = mg.user_id" +
3323
                            " AND af.proj_id       = rt.proj_id"
3324
                    );
3325
            stmt5.setFetchSize(500);
7176 dpurdie 3326
            stmt5.setInt(1, rippleEngine.getRtagId());
3327
            stmt5.setInt(2, pvId);
3328
 
3329
 
7082 dpurdie 3330
            RmResultSet rset5 = new RmResultSet(stmt5.executeQuery(), "getPackageInfo rset5");
3331
 
3332
            while ( rset5.next() )
3333
            {
3334
                p.addEmail(rset5.getString("user_email", null));
3335
            }
3336
 
3337
            rset5.close();
3338
            stmt5.close();
3339
 
3340
            // get Package build failure info...
3341
            // package version
3342
            mLogger.debug("getPackageInfo: stmt6");
3343
            PreparedStatement stmt6 = mConnection.prepareStatement(
3344
                    "select pv.pv_id, u1.user_email as creator, u2.user_email as owner, u3.user_email as modifier" +
3345
                    " from " +
3346
                    "      release_manager.release_tags rt," +
3347
                    "      release_manager.package_versions pv," +
3348
                    "      release_manager.users u1," +
3349
                    "      release_manager.users u2," +
3350
                    "      release_manager.users u3 " +
7176 dpurdie 3351
                    " where pv.pv_id=?" +  
3352
                    "   and rt.rtag_id=?" + 
7082 dpurdie 3353
                    "   and pv.build_type='A'" +
3354
                    "   and pv.dlocked='A' " +
3355
                    "   and u1.user_id=pv.creator_id" +
3356
                    "   and u2.user_id=pv.owner_id" +
3357
                    "   and u3.user_id=pv.modifier_id"
3358
                    );
3359
            stmt6.setFetchSize(500);
7176 dpurdie 3360
            stmt6.setInt(1, pvId);
3361
            stmt6.setInt(2, rippleEngine.getRtagId());
3362
 
7082 dpurdie 3363
            RmResultSet rset6 = new RmResultSet(stmt6.executeQuery(), "getPackageInfo rset6");
3364
 
3365
            while ( rset6.next() )
3366
            {
3367
                p.addEmail( rset6.getString("creator",null));
3368
                p.addEmail( rset6.getString("owner",null));
3369
                p.addEmail( rset6.getString("modifier",null));
3370
            }
3371
 
3372
            rset6.close();
3373
            stmt6.close();
3374
 
3375
            // get Package advisory ripple info
3376
            mLogger.debug("getPackageInfo: stmt7");
3377
            PreparedStatement stmt7 = mConnection.prepareStatement(
3378
                    "select pv.pv_id, pv.modified_stamp " +
3379
                    " from " +
3380
                    "      release_manager.package_versions pv," +
3381
                    "      release_manager.advisory_ripple ar " +
7176 dpurdie 3382
                    " where pv.pv_id = ?" +
3383
                    "    and ar.rtag_id= ?" +
7082 dpurdie 3384
                    "    and ar.pv_id=pv.pv_id "
3385
                    );
3386
            stmt7.setFetchSize(500);
7176 dpurdie 3387
            stmt7.setInt(1, pvId);
3388
            stmt7.setInt(2, rippleEngine.getRtagId());
3389
 
7082 dpurdie 3390
            RmResultSet rset7 = new RmResultSet(stmt7.executeQuery(), "getPackageInfo rset7");
3391
 
3392
            if( rset7.next() )
3393
            {
3394
                p.mAdvisoryRipple = true;
3395
            }
3396
 
3397
            rset7.close();
3398
            stmt7.close();            
3399
 
3400
        }
3401
        catch ( SQLException e )
3402
        {
3403
            handleSQLException(e, "");
3404
        }
3405
 
3406
        return p;
3407
    }
3408
 
7169 dpurdie 3409
    /** Extract PlanControl data for a specific release
3410
     * 
3411
     *  Overridden in ReleaseManagerUtf
3412
     * 
3413
     * @param mRtagId - Release to process
3414
     * @param mPlanControl  - Data is inserted into this object
3415
     * @throws Exception 
3416
     */
3417
    public void queryPlanControl(int mRtagId, PlanControl mPlanControl) throws Exception {
3418
        mLogger.debug("queryPlanControl {}", mRtagId);
3419
 
3420
        if ( mUseDatabase )
3421
        {
3422
            try
3423
            {
3424
                CallableStatement stmt = mConnection.prepareCall(
3425
                        "SELECT PLAN_THRESHOLD, PLAN_DROP" + 
3426
                        " FROM release_manager.release_tags rt" + 
3427
                        " WHERE rt.rtag_id  = ?"
3428
                        );
3429
                stmt.setInt(1, mRtagId);
3430
                RmResultSet rset = new RmResultSet(stmt.executeQuery(), "queryPlanControl");
3431
 
3432
                if( rset.next() )
3433
                {
3434
                    mPlanControl.setThreshold(rset.mustGetInt("PLAN_THRESHOLD"));
3435
                    mPlanControl.setDumpPlan(rset.mustGetString("PLAN_DROP"));
3436
                } else
3437
                {
3438
                    mLogger.error("queryPlanControl did not return data");
3439
                    // show stopper
3440
                    throw new Exception("queryPlanControl did not return data");
3441
                }
3442
                rset.close();
3443
                stmt.close();            
3444
            }
3445
            catch ( SQLException e )
3446
            {
3447
                handleSQLException(e, "");
3448
            }
3449
        }
3450
 
7176 dpurdie 3451
        mLogger.debug("queryPlanControl {}", mPlanControl);
7169 dpurdie 3452
    }
3453
 
7082 dpurdie 3454
    /**	Determine the version number of the base package
6914 dpurdie 3455
    *   Used in a ripple build to determine the base for calculating the next version number
3456
    *   Assumes that a database connection has been established
3457
    *   Used in Daemon Mode Only
3458
    *   
3459
    *   History: Used to determine the last non-rippled package, but this had issues [JATS-402]
3460
    *   This version will located the last release version with a check that it is not a WIP ( ie start with a '(' )
3461
    *   
3462
    *   @param pv_id	- The PVID of the package to process
3463
    *   @return         - The version number without a project suffix. Null on error. 0.0.0000 if no previous
3464
    *   @throws SQLException 
3465
    */
3466
    public String getBaseVersionNumber(int pv_id)
3467
    {
3468
    	String baseVersion = "0.0.0000";
3469
 
3470
    	try {
3471
    		CallableStatement stmt;
3472
			stmt = mConnection.prepareCall(
3473
					"SELECT pv_id,last_pv_id,pkg_version,v_ext,build_type, DLOCKED " +
3474
					" FROM " +
3475
					"  (SELECT build_type,last_pv_id,pv_id,pkg_version,v_ext, DLOCKED " +
3476
					"  FROM " +
3477
					"    (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 " +
3478
					"    FROM release_manager.package_versions pv " +
3479
					"    WHERE pv.PKG_ID IN " +
3480
					"      (SELECT pkg_id " +
3481
					"      FROM release_manager.package_versions pv " +
7169 dpurdie 3482
					"      WHERE pv.pv_id = ?" +
6914 dpurdie 3483
					"      ) " +
3484
					"    ) " +
7169 dpurdie 3485
					"    START WITH pv_id = ?" +
6914 dpurdie 3486
					"    CONNECT BY nocycle prior last_pv_id = pv_id " +
3487
					"  ) " +
7169 dpurdie 3488
					" WHERE DLOCKED = 'Y' and pkg_version not like '(%' AND pv_id != ?"
6914 dpurdie 3489
	                   //" WHERE build_type != 'Y' and pv_id != " + pv_id
3490
			        );
7169 dpurdie 3491
			stmt.setInt(1, pv_id);
3492
			stmt.setInt(2, pv_id);
3493
			stmt.setInt(3, pv_id);
3494
 
6914 dpurdie 3495
			ResultSet rset = stmt.executeQuery();
3496
 
3497
			while( rset.next() )
3498
			{
3499
				// Previous Version of this package, without the project suffix
3500
				String pkg_prevVersion = rset.getString("pkg_version");
3501
				if (pkg_prevVersion != null) 
3502
				{
3503
					String pkg_prevVext = rset.getString("v_ext");
3504
					if (pkg_prevVext != null) 
3505
					{
3506
						int endindex = pkg_prevVersion.length() - pkg_prevVext.length();
3507
						if ( endindex > 0 )
3508
						{
3509
							baseVersion = pkg_prevVersion.substring(0, endindex);
3510
						}
3511
					}
3512
				}
3513
 
3514
				// Only want the first entry
3515
				break;
3516
			}
3517
 
3518
			rset.close();
3519
			stmt.close();
3520
 
3521
    	} catch (SQLException e) {
3522
    		baseVersion = null;
7044 dpurdie 3523
    		mLogger.error("Exception for getBaseVersionNumber {}", pv_id);
6914 dpurdie 3524
		}
3525
        return baseVersion;
3526
    }
3527
 
7044 dpurdie 3528
    /** Called only in escrow mode
3529
     * 
3530
     * Used to process each package in the escrow list and to locate all dependent packages - recursively.
3531
     * 
6914 dpurdie 3532
     * if checkCollection is true, checks the pv_id is in the packageCollection
3533
     * if checkCollection is false, or the pv_id is not in the collection
7044 dpurdie 3534
     *    Traverses the pv_id package dependencies
3535
     *    for each dpv.pv_id in the resultset
6914 dpurdie 3536
     *     call traverseDependencies( packageCollection, dpv.pv_id, true )
3537
     *     if the pv_id is not in the collection, add it
7044 dpurdie 3538
     * 
3539
     *   @param packageCollection   - Collection of packages being processed
3540
     *   @param pkg                 - Current package in the collection
3541
     *   @param checkCollection     - How to handle pkg not in the collection. False: Process all package dependencies. True: Skip if package is in collection
3542
     *   @param listIterator        - List iterator being used to iterate over packageCollection. Used to insert new packages
6914 dpurdie 3543
     *   
7044 dpurdie 3544
     *   This function is called recursively
6914 dpurdie 3545
     */
7044 dpurdie 3546
    private void traverseDependencies(ArrayList<Package> packageCollection, Package pkg, boolean checkCollection, ListIterator<Package> listIterator) throws SQLException, Exception
3547
    {
3548
        mLogger.debug("traverseDependencies {}", checkCollection);
6914 dpurdie 3549
        boolean pvIdInCollection = false;
3550
 
3551
        if ( checkCollection )
3552
        {
3553
            for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); )
3554
            {
3555
                Package p = it.next();
3556
 
3557
                if ( p.mId == pkg.mId )
3558
                {
3559
                    pvIdInCollection = true;
3560
                    break;
3561
                }
3562
            }
3563
        }
3564
 
3565
        if ( !pvIdInCollection )
3566
        {
3567
            ArrayList<Package> resultset = new ArrayList<Package>();
3568
 
3569
            try
3570
            {
3571
                PreparedStatement stmt = mConnection.prepareStatement(
3572
                        "select dpv.pv_id," +
3573
                                "p.pkg_name," + 
3574
                                "dpv.pkg_version," +
3575
                                "dpv.v_ext," + 
3576
                                "release_manager.PK_RMAPI.return_vcs_tag(dpv.pv_id) AS vcsTag" + 
3577
                                " from release_manager.package_versions pv," + 
3578
                                "release_manager.package_dependencies pd," + 
3579
                                "release_manager.package_versions dpv," + 
3580
                                "release_manager.packages p" + 
7176 dpurdie 3581
                                " where pv.pv_id=?" + 
6914 dpurdie 3582
                                "   and pd.pv_id=pv.pv_id" +
3583
                                "   and dpv.pv_id=pd.dpv_id" + 
3584
                                "   and p.pkg_id=dpv.pkg_id" + 
3585
                        " order by pv.pv_id");
7176 dpurdie 3586
                stmt.setInt(1, pkg.mId);
6914 dpurdie 3587
                stmt.setFetchSize(1000);
7023 dpurdie 3588
                RmResultSet rset = new RmResultSet(stmt.executeQuery(),"traverseDependencies");
6914 dpurdie 3589
 
3590
                while (rset.next())
3591
                {
7023 dpurdie 3592
                    int pv_id = rset.mustGetKeyInt("pv_id");
3593
                    String pkg_name = rset.mustGetString("pkg_name");
3594
                    String pkg_version = rset.mustGetString("pkg_version");
3595
                    String v_ext = rset.getString("v_ext","");
3596
                    String vcs_tag = rset.getString("vcsTag","");
6914 dpurdie 3597
 
3598
                    Package p = new Package(0, pv_id, pkg_name, pkg_version, v_ext, pkg_name + "." + pkg_version, vcs_tag, 'x');
3599
                    resultset.add(p);
7163 dpurdie 3600
                    pkg.addDependency(p.mAlias, -1);
6914 dpurdie 3601
                }
3602
 
3603
                rset.close();
3604
                stmt.close();
3605
            }
3606
            catch ( SQLException e )
3607
            {
3608
                handleSQLException(e, "");
3609
            }
3610
 
7044 dpurdie 3611
            //  Process each dependent package
6914 dpurdie 3612
            for (Iterator<Package> it = resultset.iterator(); it.hasNext();)
3613
            {
3614
                Package r = it.next();
3615
                traverseDependencies(packageCollection, r, true, listIterator);
3616
 
3617
                pvIdInCollection = false;
3618
 
3619
                for (Iterator<Package> it2 = packageCollection.iterator(); it2.hasNext();)
3620
                {
3621
                    Package p = it2.next();
3622
 
3623
                    if (p.mId == r.mId)
3624
                    {
3625
                        pvIdInCollection = true;
3626
                        break;
3627
                    }
3628
                }
3629
 
3630
                if (!pvIdInCollection)
3631
                {
3632
                    // insert the Package immediately before the next Package returned by next
3633
                    // this does not change the next Package (if any) to be returned by next
3634
                    listIterator.add(r);
3635
                }
3636
 
3637
            }
3638
        }
7044 dpurdie 3639
    }
6914 dpurdie 3640
 
7044 dpurdie 3641
    /** Called only in escrow mode
3642
     * 
3643
     *  <p>Add build information to a Package
3644
     *  <br>Adds: bm_name and bsa_name, but only if they are supported
3645
     * 
3646
     * @param   rippleEngine    - Ripple Engine being used
3647
     * @param   p               - Package to process
3648
     * 
6914 dpurdie 3649
     */
3650
    private void queryBuildInfo(RippleEngine rippleEngine, Package p) throws SQLException, Exception
3651
    {
3652
        mLogger.debug("queryBuildInfo");
3653
 
3654
        try
3655
        {
3656
            CallableStatement stmt = mConnection.prepareCall("select bm.bm_name, bsa.bsa_name "
3657
                    + "from release_manager.package_versions pv," 
3658
                    + "     release_manager.package_build_info pbi,"
3659
                    + "     release_manager.build_machines bm," 
3660
                    + "     release_manager.build_standards_addendum bsa "
7169 dpurdie 3661
                    + "where pv.pv_id=?" 
6914 dpurdie 3662
                    + "   and pbi.pv_id=pv.pv_id" 
3663
                    + "   and bm.bm_id=pbi.bm_id"
3664
                    + "   and bsa.bsa_id=pbi.bsa_id " 
3665
                    + "order by pv.pv_id");
7169 dpurdie 3666
            stmt.setInt(1, p.mId);
3667
 
7023 dpurdie 3668
            RmResultSet rset = new RmResultSet (stmt.executeQuery(),"queryBuildInfo");
6914 dpurdie 3669
 
3670
            while (rset.next())
3671
            {
7023 dpurdie 3672
                String bm_name = rset.mustGetKeyString("bm_name");
3673
                String bsa_name = rset.mustGetString("bsa_name");
6914 dpurdie 3674
 
3675
                BuildStandard bs = new BuildStandard(rippleEngine, bm_name, bsa_name);
3676
 
3677
                if (bs.supportedBuildStandard())
3678
                {
3679
                    p.mBuildStandardCollection.add(bs);
3680
                }
3681
            }
3682
 
3683
            rset.close();
3684
            stmt.close();
3685
        }
3686
        catch ( SQLException e )
3687
        {
3688
            handleSQLException(e, "");
3689
        }
3690
 
3691
    }
3692
 
3693
    /**
3694
     * Find Package by pvid
3695
     * @param   id                  - pvid of package to locate
3696
     * @param   packageCollection   - Collection to scan
3697
     * @return  Package with the matching mID or NULL_PACKAGE if no package has the mID
3698
     */
7082 dpurdie 3699
    int findPackageLastId = 0;
3700
    int findPackageLastIndex = 0;
3701
    Package findPackageLastPackage = NULL_PACKAGE;
3702
 
7137 dpurdie 3703
    /**
3704
     * Reset the values cached by findPackage
3705
     * Needed when a new plan is started as the only package versions are stale
3706
     */
3707
    public void findPackageResetCache() {
3708
        findPackageLastId = 0;
3709
        findPackageLastIndex = 0;
3710
        findPackageLastPackage = NULL_PACKAGE;
3711
    }
3712
 
7082 dpurdie 3713
    public Package findPackage(int id, ArrayList<Package> packageCollection)
6914 dpurdie 3714
    {
7088 dpurdie 3715
        mLogger.debug("findPackage id {}", id);
6914 dpurdie 3716
        Package retVal = NULL_PACKAGE;
7082 dpurdie 3717
 
3718
        if (findPackageLastId != 0 && findPackageLastId == id) {
3719
            mLogger.debug("findPackage id {} - cache hit", id);
3720
            retVal = findPackageLastPackage;
3721
        }
3722
        else
6914 dpurdie 3723
        {
7082 dpurdie 3724
            int index = 0;
3725
            findPackageLastIndex = -1;
3726
 
3727
            for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); index++ )
6914 dpurdie 3728
            {
7082 dpurdie 3729
                Package p = it.next();
3730
 
3731
                if ( p.mId == id )
3732
                {
3733
                    findPackageLastId = id;
3734
                    findPackageLastPackage = p;
3735
                    findPackageLastIndex = index;
3736
                    retVal = p;
3737
                    break;
3738
                }
6914 dpurdie 3739
            }
3740
        }
3741
 
7088 dpurdie 3742
        mLogger.debug("findPackage id {} returned {}", id, retVal.mName);
6914 dpurdie 3743
        return retVal;
3744
    }
3745
 
3746
    /**
3747
     * Find Package by package alias
3748
     * @param   alias               - alias of package to locate
3749
     * @param   packageCollection   - Collection to scan
3750
     * @return  Package with the matching mAlias or NULL_PACKAGE if no package has the mAlias
3751
     */
3752
    protected Package findPackage(String alias, ArrayList<Package> packageCollection)
3753
    {
7088 dpurdie 3754
        mLogger.debug("findPackage alias {}", alias);
6914 dpurdie 3755
        Package retVal = NULL_PACKAGE;
7082 dpurdie 3756
        int index = 0;
3757
        findPackageLastIndex = -1;
6914 dpurdie 3758
 
7082 dpurdie 3759
        for (Iterator<Package> it = packageCollection.iterator(); it.hasNext(); index++)
6914 dpurdie 3760
        {
3761
            Package p = it.next();
3762
 
3763
            if ( p.mAlias.compareTo( alias ) == 0 )
3764
            {
3765
                retVal = p;
7082 dpurdie 3766
                findPackageLastId = p.mId;
3767
                findPackageLastPackage = p;
3768
                findPackageLastIndex = index;
6914 dpurdie 3769
                break;
3770
            }
3771
        }
3772
 
7088 dpurdie 3773
        mLogger.info("findPackage alias {} returned {}", alias, retVal.mName);
6914 dpurdie 3774
        return retVal;
3775
    }
7137 dpurdie 3776
 
3777
 
6914 dpurdie 3778
 
3779
    /**only used in daemon mode to determine version existence in the database
3780
     *  1 select pkg_id from release_manager.package_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3781
     *  2 select pkg_id from release_manager.planned_versions where pkg_id=<pkg_id> and pkg_version=<pkg_version>;
3782
     * returns true if either resultset contains one record to indicate it already exists
3783
     */
3784
    boolean queryPackageVersions(int pkg_id, String pkg_version) throws SQLException, Exception
3785
    {
3786
        mLogger.debug("queryPackageVersions");
3787
        boolean retVal = false;
3788
 
3789
        if ( mUseDatabase )
3790
        {
3791
            try
3792
            {
3793
                mLogger.info("queryPackageVersions release_manager.package_versions");
3794
                CallableStatement stmt1 = mConnection.prepareCall(
3795
                    "select pkg_id" +
3796
                    " from release_manager.package_versions" +
7169 dpurdie 3797
                    " where pkg_id=?" + 
3798
                    " and pkg_version=?");
3799
                stmt1.setInt(1, pkg_id);
3800
                stmt1.setString(2, pkg_version);
3801
 
6914 dpurdie 3802
                ResultSet rset1 = stmt1.executeQuery();
3803
                int rsetSize = 0;
3804
 
3805
                while( rset1.next() )
3806
                {
3807
                    rsetSize++;
3808
                }
3809
 
3810
                rset1.close();
3811
                stmt1.close();
3812
 
3813
                if ( rsetSize > 1 )
3814
                {
7044 dpurdie 3815
                    String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3816
                    mLogger.error(msg);
6914 dpurdie 3817
                    // show stopper
7044 dpurdie 3818
                    throw new Exception(msg);
6914 dpurdie 3819
                }
3820
 
3821
                if ( rsetSize == 1 )
3822
                {
3823
                    retVal = true;
3824
                }
3825
                else
3826
                {
3827
                    mLogger.info("queryPackageVersions release_manager.planned_versions");
3828
                    CallableStatement stmt2 = mConnection.prepareCall(
3829
                        "select pkg_id" +
3830
                        " from release_manager.planned_versions" +
7169 dpurdie 3831
                        " where pkg_id=?" + 
3832
                        " and pkg_version=?");
3833
                    stmt2.setInt(1, pkg_id);
3834
                    stmt2.setString(2, pkg_version);
3835
 
6914 dpurdie 3836
                    ResultSet rset2 = stmt2.executeQuery();
3837
                    rsetSize = 0;
3838
 
3839
                    while( rset2.next() )
3840
                    {
3841
                        rsetSize++;
3842
                    }
3843
 
3844
                    rset2.close();
3845
                    stmt2.close();
3846
 
3847
                    if ( rsetSize > 1 )
3848
                    {
7044 dpurdie 3849
                        String msg = "queryPackageVersions rsetSize > 1 " + pkg_id + " " + pkg_version;
3850
                        mLogger.error(msg);
6914 dpurdie 3851
                        // show stopper
7044 dpurdie 3852
                        throw new Exception(msg);
6914 dpurdie 3853
                    }
3854
 
3855
                    if ( rsetSize == 1 )
3856
                    {
3857
                        retVal = true;
3858
                    }
3859
                }
3860
            }
3861
            catch ( SQLException e )
3862
            {
3863
                handleSQLException(e, "");
3864
            }
3865
        }
3866
 
7176 dpurdie 3867
        mLogger.debug("queryPackageVersions returned {}", retVal);
6914 dpurdie 3868
        return retVal;
3869
    }
3870
 
3871
    /**
3872
     * Determine the set of packages that have been excluded from the build 
3873
     * These are packages that have been marked as do_not_ripple 
3874
     *  
3875
     * Overridden in ReleaseManagerUtf
3876
     * 
3877
     * @param buildExclusionCollection
3878
     * @param baseline The rtag_id of the release to examine
3879
     * 
3880
     * @exception SQLException
3881
     * @exception Exception
3882
     */
3883
    public void queryBuildExclusions(List<BuildExclusion> buildExclusionCollection, int baseline) throws SQLException, Exception
3884
    {
7044 dpurdie 3885
        mLogger.debug("queryBuildExclusions {}", baseline);
6914 dpurdie 3886
 
3887
        try
3888
        {
3889
            PreparedStatement stmt = mConnection.prepareStatement(
3890
                    "select pv_id, root_pv_id, root_cause" +
3891
                    " from release_manager.do_not_ripple" + 
7176 dpurdie 3892
                    " where rtag_id=?");
6914 dpurdie 3893
            stmt.setFetchSize(1000);
7176 dpurdie 3894
            stmt.setInt(1, baseline);
3895
 
7023 dpurdie 3896
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryBuildExclusions");
6914 dpurdie 3897
 
3898
            while( rset.next() )
3899
            {
7023 dpurdie 3900
                int pvId = rset.mustGetKeyInt("pv_id");
3901
                int rootPvId = rset.getInt("root_pv_id", -1);
3902
                String rootCause = rset.getString("root_cause", null);
6914 dpurdie 3903
 
3904
                // force email notification by using a zero test build instruction
3905
                BuildExclusion buildExclusion = new BuildExclusion(pvId, rootPvId, rootCause, 0);
7032 dpurdie 3906
                buildExclusion.setImported();
6914 dpurdie 3907
                buildExclusionCollection.add(buildExclusion);
3908
            }
3909
 
3910
            rset.close();
3911
            stmt.close();
3912
        }
3913
        catch ( SQLException e )
3914
        {
3915
            handleSQLException(e, "");
3916
        }
3917
    }
3918
 
3919
    /**
7032 dpurdie 3920
     * Execute the Exclude_Indirect_From_Build stored procedure
6914 dpurdie 3921
     *  Note: Execute_Indirect_From_Build will delete matching do_not_ripple
3922
     *        rows prior to an insertion - this is crucial!!
7032 dpurdie 3923
     *        
3924
     * Note: The name 'Execute_Indirect_From_Build' is misleading as it appears to be used for both direct and indirect
3925
     *       exclusions.
3926
     * 
6914 dpurdie 3927
     * @param hasConnection        IN True. Use existing connection and will not commit the operation
3928
     * @param packageVersionId     IN passed to Exclude_Indirect_From_Build
3929
     * @param packageVersion       IN passed to Exclude_Indirect_From_Build
3930
     * @param rtagId               IN passed to Exclude_Indirect_From_Build
3931
     * @param rootPvId             IN passed to Exclude_Indirect_From_Build
3932
     * @param rootCause            IN passed to Exclude_Indirect_From_Build
3933
     * @param rootFile             IN passed to Exclude_Indirect_From_Build
3934
     * @param supercede            IN checks for a row with a matching packageVersionId and rtagId when false
3935
     *                                such a row will prevent the execution of Exclude_Indirect_From_Build
3936
     * @param testBuildInstruction IN will prevent the execution of Exclude_Indirect_From_Build true
3937
     * 
3938
     * @exception SQLException
3939
     * @exception Exception
3940
     */
3941
    public void excludeFromBuild(
3942
            boolean hasConnection, 
3943
            int packageVersionId, 
3944
            String packageVersion, 
3945
            int rtagId,
3946
            String rootPvId, 
3947
            String rootCause,
3948
            String rootFile,
3949
            boolean supercede, Boolean testBuildInstruction) throws SQLException, Exception
3950
    {
7044 dpurdie 3951
        mLogger.debug("excludeFromBuild {}", packageVersionId);
6914 dpurdie 3952
 
3953
        //  If a Test Build, then don't excluded package
3954
        if ( testBuildInstruction )
3955
        {
3956
            return;
3957
        }
3958
 
3959
        if ( mUseDatabase )
3960
        {
3961
            try
3962
            {
3963
                if (!hasConnection)
3964
                    connect();
3965
 
3966
                boolean exist = false;
7032 dpurdie 3967
                boolean dbIsIndirect = false;
3968
                boolean entryIsIndirect = (rootPvId != null);
6914 dpurdie 3969
 
3970
                if ( !supercede )
3971
                {
3972
                    // do not exclude a package already excluded ie let the first build failure count
3973
                    // there is a window of opportunity here, but it is worth doing
3974
                    // scenario 1
3975
                    //      1 this query indicates no build failure exists on this version
3976
                    //      2 another build machine reports a build failure on this version
3977
                    //      3 this is then overridden by this thread
3978
                    // does not matter
3979
                    // doing this works well for the following
3980
                    // scenario 2
3981
                    //      1 this query (run by a slave) indicates no build failure exists on this version
3982
                    //      2 build failure is reported
3983
                    //      3 master build machine detects slave in state waiting
3984
                    //      4 master daemon discovers slave did not deliver artifacts
3985
                    //      5 master daemon is prevented from overriding the build failure
7032 dpurdie 3986
                    //
3987
                    // Another complication
3988
                    //  If this is a direct exclusion (rootPvid) is null and the entry in the table is an indirect exclusion
3989
                    //  then we should delete the indirect exclusion and replace it with a direct exclusion
3990
                    //
7169 dpurdie 3991
                    CallableStatement stmt = mConnection.prepareCall(
3992
                            "select pv_id, root_pv_id from release_manager.do_not_ripple where pv_id=? and rtag_id=?");
3993
                    stmt.setInt(1, packageVersionId);
3994
                    stmt.setInt(2, rtagId);
3995
 
6914 dpurdie 3996
                    ResultSet rset = stmt.executeQuery();
3997
 
3998
                    while( rset.next() )
3999
                    {
4000
                        exist = true;
7032 dpurdie 4001
                        rset.getInt("root_pv_id");
4002
                        dbIsIndirect = ! rset.wasNull();
4003
 
4004
                        // Override an indirect database entry with a direct exclusion
4005
                        if ( dbIsIndirect && ! entryIsIndirect ) {
4006
                            exist = false;
4007
                        }
4008
 
6914 dpurdie 4009
                        break;
4010
                    }
4011
 
4012
                    rset.close();
4013
                    stmt.close();
4014
                }
4015
 
4016
                if ( !exist )
4017
                {
4018
                    CallableStatement stmt = mConnection.prepareCall( "begin ? := PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD(?,?,?,?,?,?,?); end;" );
4019
                    stmt.registerOutParameter( 1, Types.INTEGER);
4020
                    stmt.setInt    ( 2, packageVersionId );
4021
                    stmt.setString ( 3, packageVersion );
4022
                    stmt.setInt    ( 4, rtagId );
4023
                    stmt.setString ( 5, "buildadm" );
4024
                    stmt.setString ( 6, rootPvId);
4025
                    stmt.setString ( 7, rootCause);
4026
                    stmt.setString ( 8, rootFile);
4027
                    stmt.executeUpdate();
4028
                    int result = stmt.getInt( 1 );
4029
 
4030
                    if ( result != 0 )
4031
                    {
4032
                        // flag build failure
7044 dpurdie 4033
                        mLogger.error( "excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned {}",  result );
6914 dpurdie 4034
                        throw new Exception("excludeFromBuild show stopper PK_RMAPI.EXCLUDE_INDIRECT_FROM_BUILD failed, returned " + result);
4035
                    }
4036
                    stmt.close();
4037
                    if (!hasConnection )
4038
                        commit();
4039
                }
4040
            }
4041
            catch ( SQLException e )
4042
            {
4043
                handleSQLException(e, "");
4044
            }
4045
            finally
4046
            {
4047
                // this block is executed regardless of what happens in the try block
4048
                // even if an exception is thrown
4049
                // ensure disconnect
4050
                if (!hasConnection )
4051
                    disconnect();
4052
            }
4053
        }
4054
    }
4055
 
4056
    /**
4057
     * Removes an excluded package from the do_not_ripple table, thereby including the package back into the build set.
4058
     * The method does not remove packages that were manually added to the DNR table, as those
4059
     * packages are not in the domain of the buildtool.
4060
     * 
4061
     * @param packageVersionId Packages PVID
4062
     * @param rtagId           The RTAG id of the release to consider
4063
     * 
4064
     * @exception SQLException
4065
     * @exception Exception
4066
     */
4067
 
4068
    public void includeToBuild(int packageVersionId, int rtagId) throws SQLException, Exception
4069
    {
7044 dpurdie 4070
        mLogger.debug("includeToBuild {}", packageVersionId);
6914 dpurdie 4071
        if ( mUseDatabase )
4072
        {
4073
            try
4074
            {
4075
                CallableStatement stmt = mConnection.prepareCall(
4076
                    "delete from release_manager.do_not_ripple " +
7169 dpurdie 4077
                    "  where rtag_id=?" + 
4078
                    "  and pv_id=?" +
6914 dpurdie 4079
                    "  and (root_pv_id is not NULL or root_cause is not NULL or root_file is not NULL)"
4080
                    );
7169 dpurdie 4081
                stmt.setInt(1, rtagId);
4082
                stmt.setInt(2, packageVersionId);
4083
 
6914 dpurdie 4084
                stmt.executeUpdate();
4085
                stmt.close();
4086
            }
4087
            catch ( SQLException e )
4088
            {
4089
                handleSQLException(e, "");
4090
            }
4091
        }
4092
    }
4093
 
4094
 
4095
 
4096
 
4097
    /**queries the RUN_LEVEL table using the rcon_id primary key
4098
     * handles database connection and disconnection
4099
     * returns the current_build_files
4100
     * implements the sequence diagram consume build files 
4101
     *  
4102
     * Used by the Slave Daemon
4103
     * 
4104
     *  @param rcon_id - My release config id
4105
     *  @return The buildFile content. Will be null if none is found
4106
     */
4107
    public String queryBuildFile(int rcon_id) throws SQLException, Exception
4108
    {
4109
        String buildFile = null;
4110
 
7044 dpurdie 4111
        mLogger.debug("queryRunLevel 1 rcon_id {}", rcon_id);
6914 dpurdie 4112
        if ( !mUseDatabase )
4113
        {
4114
            mLogger.info("queryRunLevel 1 !mUseDatabase");
4115
            buildFile = "unit test build file content";
4116
        }
4117
        else
4118
        {
4119
            try
4120
            {
4121
                connect();
7169 dpurdie 4122
                CallableStatement stmt = mConnection.prepareCall("select current_build_files from release_manager.run_level where rcon_id=?");
4123
                stmt.setInt(1, rcon_id);
6914 dpurdie 4124
                ResultSet rset = stmt.executeQuery();
4125
                int rsetSize = 0;
4126
 
4127
                while( rset.next() )
4128
                {
4129
                    rsetSize++;
4130
                    buildFile = rset.getString("current_build_files");
4131
                }
4132
 
4133
                if ( rsetSize > 1 )
4134
                {
7033 dpurdie 4135
                    mLogger.error("queryRunLevel 1 rsetSize > 1");
6914 dpurdie 4136
                    // show stopper
4137
                    throw new Exception("queryRunLevel 1 rsetSize > 1");
4138
                }
4139
 
4140
                rset.close();
4141
                stmt.close();
4142
            }
4143
            catch ( SQLException e )
4144
            {
4145
                handleSQLException(e, "");
4146
            }
4147
            finally
4148
            {
4149
                // this block is executed regardless of what happens in the try block
4150
                // even if an exception is thrown
4151
                // ensure disconnect
4152
                disconnect();
4153
            }
4154
        }
4155
 
4156
        return buildFile;
4157
    }
4158
 
4159
    /** Updates mRunLevelCollection
4160
     *  Removes all elements from mRunLevelCollection, then queries the Database
4161
     *  and re-populates the structure.
4162
     *  
4163
     *  Used to determine which slave daemons the master needs to wait upon.
4164
     *  
4165
     *  Ignores entries that are disabled
4166
     *  Ignore entries that have been 'unlinked' - they have no active machine configuration
4167
     *
4168
     *   @param	rtag_id	- Release Tag
4169
     *  
4170
     *	Used by the Master Daemon 
4171
     * 	Overridden in ReleaseManagerUtf 
4172
     */
4173
    public void queryRunLevel(final int rtag_id) throws SQLException, Exception
4174
    {
7044 dpurdie 4175
        mLogger.debug("queryRunLevel 2 rtag_id {}", rtag_id);
6914 dpurdie 4176
 
4177
        mRunLevelCollection.clear();
4178
 
4179
        try
4180
        {
4181
            connect();
4182
            CallableStatement stmt = mConnection.prepareCall(
4183
                    "SELECT rl.rcon_id," +
4184
                    "  rl.current_run_level," +
4185
                    "  NVL(rl.pause,0) as pause," +
4186
                    "  rc.daemon_mode," +
4187
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4188
                    " FROM release_manager.release_config rc," +
4189
                    "     release_manager.run_level rl" +
7169 dpurdie 4190
                    " WHERE rc.rtag_id = ?" +
6914 dpurdie 4191
                    " AND   rl.rcon_id = rc.rcon_id" +
4192
                    " AND   rc.bmcon_id is not NULL");
4193
            stmt.setFetchSize(20);
7169 dpurdie 4194
            stmt.setInt(1, rtag_id);
7023 dpurdie 4195
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"queryRunLevel 2");
6914 dpurdie 4196
            int rcon_id = 0;
4197
            int current_run_level = 0;
4198
            String modeString;
4199
            char mode;
4200
            int pause = 0;
4201
            int buildFilePresent = 0;
4202
 
4203
            while( rset.next() )
4204
            {
7023 dpurdie 4205
                rcon_id = rset.mustGetKeyInt("rcon_id");
4206
                modeString = rset.mustGetString("daemon_mode");
6914 dpurdie 4207
                mode = modeString.charAt(0);
7023 dpurdie 4208
                buildFilePresent = rset.getInt("bfPresent",0);
4209
                current_run_level = rset.getInt("current_run_level", BuildState.DB_IDLE.toValue());
6914 dpurdie 4210
 
4211
                //
4212
                //  Pause: null -> 0 == Run
4213
                //         1         == Pause
4214
                //         2         == Disabled
4215
                //
7023 dpurdie 4216
                pause = rset.getInt("pause", 0);
6914 dpurdie 4217
 
4218
                //  Ignore disabled entries
4219
                if ( pause <= 1 )
4220
                {
4221
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, mode, buildFilePresent);
4222
                    mRunLevelCollection.add(runLevel);
4223
                }
4224
            }
4225
 
4226
            rset.close();
4227
            stmt.close();
4228
        }
4229
        catch ( SQLException e )
4230
        {
4231
            handleSQLException(e, "");
4232
        }
4233
        finally
4234
        {
4235
            // this block is executed regardless of what happens in the try block
4236
            // even if an exception is thrown
4237
            // ensure disconnect
4238
            disconnect();
4239
        }
4240
    }
4241
 
4242
    /**
4243
     * Removes all elements and then re-populates mRunLevelCollection
4244
     * 
4245
     * Queries the RM database to determine the run_level of the current daemon.
4246
     * Populates the mRunLevelCollection with the query result set 
4247
     *  
4248
     * Used to determine if the (Slave) thread should still be running
4249
     *  
4250
     * Used by the Slave Daemon 
4251
     * Overridden in ReleaseManagerUtf 
4252
     * 
4253
     * @param rcon_id     Identify the Release_Config table entry for the daemon
4254
     * @param hostname    Name of the host machine
4255
     * @param daemon_mode Specifies the current daemon type
4256
     * 
4257
     * @exception SQLException
4258
     *                      Database connection errors
4259
     *                      Bad SQL statement
4260
     * @exception Exception Too many rows extracted from the database
4261
     *                      Empty(NULL) data in database
4262
     */
4263
    public void querySingleRunLevel(final int rcon_id, String hostname, char daemon_mode) throws SQLException, Exception
4264
    {
7044 dpurdie 4265
        mLogger.debug("querySingleRunLevel rcon_id {}", rcon_id);
6914 dpurdie 4266
        mRunLevelCollection.clear();
4267
 
4268
        try
4269
        {
4270
            connect();
4271
 
4272
            CallableStatement stmt = mConnection.prepareCall(
4273
                    "select rl.rcon_id, "+
4274
                    "  rl.current_run_level,"+
4275
                    "  NVL(rl.pause,0) as pause," +
4276
                    "  NVL2(rl.CURRENT_BUILD_FILES, 1 , 0) as bfPresent" +
4277
                    " from release_manager.run_level rl,"+
4278
                    "   release_manager.release_config rc" +
4279
                    " where rl.rcon_id = rc.rcon_id" +
7169 dpurdie 4280
                    "   AND rc.rcon_id=?" +
6914 dpurdie 4281
                    "   AND rc.bmcon_id is not NULL" +
7169 dpurdie 4282
                    "   AND rc.daemon_mode=?" +
4283
                    "   AND UPPER(rc.daemon_hostname)=UPPER(?)"
6914 dpurdie 4284
                    );
7169 dpurdie 4285
            stmt.setInt(1, rcon_id);
4286
            stmt.setString(2, String.valueOf(daemon_mode));
4287
            stmt.setString(3, hostname);
4288
 
7023 dpurdie 4289
            RmResultSet rset = new RmResultSet(stmt.executeQuery(),"querySingleRunLevel");
6914 dpurdie 4290
            int rsetSize = 0;
4291
            int current_run_level = 0;
4292
            int pause = 0;
4293
            int buildFilePresent = 0;
4294
 
4295
            while( rset.next() )
4296
            {
4297
                rsetSize++;
7023 dpurdie 4298
                current_run_level = rset.mustGetInt("current_run_level");
4299
                buildFilePresent = rset.getInt("bfPresent",0);
6914 dpurdie 4300
 
4301
                //
4302
                //  Pause: null -> 0 == Run
4303
                //         1         == Pause
4304
                //         2         == Disabled
4305
                //
7023 dpurdie 4306
                pause = rset.getInt("pause",0);
6914 dpurdie 4307
 
4308
                //  Ignore disabled daemons
4309
                if ( pause <= 1)
4310
                {
4311
                    RunLevelData runLevel = new RunLevelData(rcon_id, current_run_level, daemon_mode, buildFilePresent);
4312
                    mRunLevelCollection.add(runLevel);
4313
                }
4314
            }
4315
 
4316
            rset.close();
4317
            stmt.close();
4318
 
4319
            //  Must have no more than one record
4320
            //  Will have none if this daemon is no longer a part of the build set
4321
            //
4322
            if ( rsetSize > 1 )
4323
            {
4324
                //  show stopper
4325
                //  More rows than expected returned from the database
7033 dpurdie 4326
                mLogger.error("querySingleRunLevel rsetSize > 1");
6914 dpurdie 4327
                throw new Exception("querySingleRunLevel rsetSize > 1");
4328
            }
4329
        }
4330
        catch ( SQLException e )
4331
        {
4332
            handleSQLException(e, "");
4333
        }
4334
        finally
4335
        {
4336
            // this block is executed regardless of what happens in the try block
4337
            // even if an exception is thrown
4338
            // ensure disconnect
4339
            disconnect();
4340
        }
4341
    }
4342
 
4343
    /**Queries the RUN_LEVEL_SCHEDULE table to determine if we can proceed
4344
     * <br>Will not proceed if:
4345
     *      <br>- Inside a scheduled downtime
4346
     *      <br>- Indefinite pause present
4347
     * 
4348
     * <br>Should delete rows with a non NULL indefinite pause (but doesn't appear too)
4349
     *  
4350
     * <br>Assumes connection to database has been established
4351
     * 
4352
     * @param   resumeTime.value  Returns date-time when daemon can run again 
4353
     * 
4354
     * @return  False: if a row in the query result set indicates build service downtime is scheduled
4355
     *      <br>False: if a row in the query result set has a non NULL indefinite_pause
4356
     */
4357
    public boolean queryRunLevelSchedule(MutableDate resumeTime) throws SQLException, Exception
4358
    {
4359
        mLogger.debug("queryRunLevelSchedule");
4360
        boolean retVal = true;
4361
 
4362
        if ( mUseDatabase )
4363
        {
4364
            //
4365
            //  Clean up the run_level_schedule table by deleting out of date entries
4366
            //
4367
            try
4368
            {
4369
                CallableStatement stmt = mConnection.prepareCall( "BEGIN PK_BUILDAPI.DELETE_OUT_OF_DATE_SCHEDULE;   END;" );
4370
                stmt.executeUpdate();
4371
                stmt.close();
4372
                commit();
4373
            }
4374
            catch ( SQLException e )
4375
            {
4376
                handleSQLException(e, ":1");
4377
            }
4378
 
4379
            try
4380
            {
4381
                //  Extract info from the database
4382
                //
4383
                CallableStatement stmt = mConnection.prepareCall(
4384
                        "select scheduled_pause, scheduled_resume, repeat, indefinite_pause" + 
4385
                        " from release_manager.run_level_schedule");
4386
                ResultSet rset = stmt.executeQuery();
4387
                Date now = new Date();
4388
 
4389
                //
4390
                //  Scan the database information and determine if there is any reason
4391
                //  to pause. Terminate the loop on the first excuse to pause
4392
                //  as indefinite pause may have multiple (lots) of entries in the data
4393
                //  base.
4394
                //
4395
                while( retVal && rset.next() )
4396
                {
4397
                    //
4398
                    //  Examine the current row from the data base
4399
                    //  Expect one of two forms:
4400
                    //    1) scheduled_pause
4401
                    //       Must also have a scheduled_resume and a repeat
4402
                    //    2) indefinite_pause
4403
                    //
4404
 
4405
                    //  Look for scheduled_pause style of entry
4406
                    //
4407
                    Timestamp sp = rset.getTimestamp("scheduled_pause");
4408
                    if ( sp != null )
4409
                    {
4410
                        Date scheduledPause = new Date( sp.getTime() );
4411
                        Timestamp sr = rset.getTimestamp("scheduled_resume");
4412
 
4413
                        if ( sr != null )
4414
                        {
4415
                            Date scheduledResume = new Date( sr.getTime() );
4416
                            int repeat = rset.getInt("repeat");
7176 dpurdie 4417
                            mLogger.debug("queryRunLevelSchedule repeat {}", repeat);
6914 dpurdie 4418
 
4419
                            //
4420
                            //  Have scheduled_pause and scheduled_resume
4421
                            //  Examine the repeat field and determine how these are used
4422
                            //  Supported repeat:
4423
                            //      0:Once Only
4424
                            //      1:Daily           Year, Month and Day information is ignored
4425
                            //      7:Weekly          Only day of week is utilized
4426
                            //
4427
                            if ( !rset.wasNull() )
4428
                            {
4429
                                GregorianCalendar startOfDowntime = new GregorianCalendar();
4430
                                GregorianCalendar endOfDowntime = new GregorianCalendar();
4431
                                GregorianCalendar clock = new GregorianCalendar();
4432
 
4433
                                switch( repeat )
4434
                                {
4435
                                    case 0:
4436
                                        // Once Only
4437
                                        // Simple check between start and end date-times
4438
                                        if ( scheduledPause.before(now) && scheduledResume.after(now) )
4439
                                        {
4440
                                            mLogger.warn("queryRunLevelSchedule one off scheduled downtime");
4441
                                            resumeTime.value = scheduledResume;
4442
                                            retVal = false;
4443
                                        }
4444
                                        break;
4445
 
4446
                                    case 1:
4447
 
4448
                                        //  Daily
4449
                                        //  Create start and end times, then massage some fields
4450
                                        //  to reflect todays date.
4451
                                        //  Use start and end times from scheduled_pause and scheduled_resume
4452
                                        //
4453
 
4454
                                        startOfDowntime.setTime(scheduledPause);
4455
                                        endOfDowntime.setTime(scheduledResume);
4456
                                        clock.setTime(now);
4457
 
4458
                                        // Force date fields to todays date
4459
                                        endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4460
                                        startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4461
 
4462
                                        if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4463
                                        {
4464
                                            mLogger.warn("queryRunLevelSchedule daily scheduled downtime");
4465
                                            resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4466
                                            retVal = false;
4467
                                        }
4468
                                        break;
4469
 
4470
                                    case 7:
4471
 
4472
                                        // Weekly
4473
                                        // Create start and end times, then massage some fields
4474
                                        // to reflect todays date.
4475
                                        // Use DayOfWeek and time from scheduled_pause
4476
                                        // Use time from scheduled_resume
4477
                                        //
4478
                                        startOfDowntime.setTime(scheduledPause);
4479
                                        endOfDowntime.setTime(scheduledResume);
4480
                                        clock.setTime(now);
4481
 
4482
                                        // Only interested in one day of the week
4483
                                        if ( startOfDowntime.get(Calendar.DAY_OF_WEEK) == clock.get(Calendar.DAY_OF_WEEK) )
4484
                                        {
4485
                                            endOfDowntime.set  ( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4486
                                            startOfDowntime.set( clock.get(Calendar.YEAR), clock.get(Calendar.MONTH), clock.get(Calendar.DAY_OF_MONTH) );
4487
 
4488
                                            if ( startOfDowntime.before(clock) && endOfDowntime.after(clock) )
4489
                                            {
4490
                                                mLogger.warn("queryRunLevelSchedule weekly scheduled downtime");
4491
                                                resumeTime.value.setTime(endOfDowntime.getTimeInMillis());
4492
                                                retVal = false;
4493
                                            }
4494
                                        }
4495
                                        break;
4496
 
4497
                                   default:
4498
                                       //
4499
                                       //   Unexpected value
4500
                                       break;
4501
                                }
4502
                            }
4503
                        }
4504
                    }
4505
 
4506
                    //
4507
                    //  Look for indefinite_pause style of entry
4508
                    //  Note: due to an implementation error there may be many
4509
                    //        rows that match. We only need one. The scan will
4510
                    //        be terminated if we find any
4511
                    //  
4512
                    //
4513
                    String ip = rset.getString("indefinite_pause");
4514
                    if ( ip != null )
4515
                    {
4516
                        // indefinite pause is non null
4517
                        mLogger.warn("queryRunLevelSchedule indefinite pause");
4518
                        GregorianCalendar clock = new GregorianCalendar();
4519
                        clock.setTime(now);
4520
                        // wait a minute
4521
                        resumeTime.value.setTime(clock.getTimeInMillis() + 60000);
4522
                        retVal = false;
4523
                    }
4524
                }
4525
 
4526
                rset.close();
4527
                stmt.close();
4528
            }
4529
            catch ( SQLException e )
4530
            {
4531
                handleSQLException(e, ":2");
4532
            }
4533
        }
4534
 
7176 dpurdie 4535
        mLogger.debug("queryRunLevelSchedule returning {}", retVal);
6914 dpurdie 4536
        return retVal;
4537
    }
4538
 
4539
    /**persists the runLevel in the RUN_LEVEL table for the rcon_id primary key
4540
     * 
4541
     * Overridden in the UTF
4542
     * 
4543
     * @param   rcon_id         Identifies the Release Connection (daemon)
4544
     * @param   runLevel        The run level to set
4545
     * 
4546
     */
4547
    public void updateCurrentRunLevel(final int rcon_id, final int runLevel) throws SQLException, Exception
4548
    {
4549
        mLogger.debug("updateCurrentRunLevel");
4550
 
4551
        try
4552
        {
4553
            connect();
4554
 
7044 dpurdie 4555
            mLogger.warn("updateCurrentRunLevel: Set Runlevel:{}, rconId:{}", runLevel, rcon_id);
7169 dpurdie 4556
            PreparedStatement stmt = mConnection.prepareCall(
4557
                    "update release_manager.run_level set current_run_level=?, keep_alive=SYSDATE where rcon_id=?");
4558
            stmt.setInt(1, runLevel);
4559
            stmt.setInt(2, rcon_id);
6914 dpurdie 4560
            stmt.executeUpdate();
4561
            stmt.close();
4562
 
4563
            mLogger.info("updateCurrentRunLevel: committing");
4564
            commit();
4565
            mLogger.info("updateCurrentRunLevel: committed");
4566
        }
4567
        catch ( SQLException e )
4568
        {
4569
            handleSQLException(e, "");
4570
        }
4571
        finally
4572
        {
4573
            // this block is executed regardless of what happens in the try block
4574
            // even if an exception is thrown
4575
            // ensure disconnect
4576
            disconnect();
4577
        }
4578
 
4579
    }
4580
 
4581
    /** Report the current build plan
4582
     *  This is only for display purposes
4583
     *  Assume a connection has been established. Will not commit if the operation is covered by the Mutex
4584
     *  
4585
     * @param mRtagId - Release we are building
4586
     * @param mBuildOrder - Ordered list of PackageVersions that we plan to build
4587
     * @throws Exception 
4588
     * @throws SQLException 
4589
     */
7088 dpurdie 4590
    public void reportPlan(int mRtagId, ArrayList<PlannedPackage> mBuildOrder) throws SQLException, Exception {
7044 dpurdie 4591
        mLogger.debug("reportPlan {}", mRtagId);
6914 dpurdie 4592
 
4593
        if ( mUseDatabase )
4594
        {
4595
            try
4596
            {
7082 dpurdie 4597
                Iterator<PlannedPackage> it = mBuildOrder.iterator();
6914 dpurdie 4598
                int fragment = 0;
4599
                CallableStatement stmt = mConnection.prepareCall( "call PK_BUILDAPI.set_build_plan(?,?,?)" );
4600
 
4601
                do {
4602
                    //
4603
                    // Generate a comma separated list of PVIDs
4604
                    // Limit the length of the string since we can only pump 4000 chars into a string
4605
                    // Allow 10 chars per PV_ID
4606
                    //
4607
                    StringBuilder pvList = new StringBuilder();
4608
                    String joiner = "";
4609
 
4610
                    while ( pvList.length() < 3000  && it.hasNext() )
4611
                    {
7082 dpurdie 4612
                        PlannedPackage p = it.next();
6914 dpurdie 4613
                        pvList.append(joiner);
7082 dpurdie 4614
                        pvList.append(p.mPkg.mId);
6914 dpurdie 4615
                        joiner = ",";
4616
                    }
4617
 
4618
                    //  Terminate if we have nothing to add and its not the first pass
4619
                    if (pvList.length() <= 0 && fragment != 0)
4620
                    {
4621
                        break;
4622
                    }
4623
 
4624
                    //
4625
                    //  Insert data - one fragment at a time
4626
                    //
4627
                    stmt.setInt    ( 1, mRtagId );
4628
                    stmt.setInt    ( 2, fragment );
4629
                    stmt.setString ( 3, pvList.toString() );
4630
                    stmt.executeUpdate();
4631
                    fragment++;
4632
 
4633
                } while(true);
4634
 
4635
                stmt.close();
4636
 
4637
                //  Commit only if not covered by the Mutex
4638
                if ( ! mDoNotCommit )
4639
                    commit();
4640
            }
4641
            catch ( SQLException e )
4642
            {
4643
                handleSQLException(e, "");
4644
            }
4645
            finally
4646
            {
4647
                // this block is executed regardless of what happens in the try block
4648
                // even if an exception is thrown
4649
            }
4650
        }
4651
    }
4652
 
4653
    public void updateBuildDuration(int pvId, int duration) throws Exception {
7044 dpurdie 4654
        mLogger.debug("updateBuildDuration {}:{}", pvId, duration);
6914 dpurdie 4655
        if ( mUseDatabase )
4656
        {
4657
            try
4658
            {
4659
                connect();
4660
 
7176 dpurdie 4661
                PreparedStatement stmt = mConnection.prepareStatement("update release_manager.package_versions set BUILD_TIME = ? where pv_id = ?");
6914 dpurdie 4662
                stmt.setLong( 1,duration );
4663
                stmt.setLong( 2,pvId );
4664
                stmt.executeUpdate();
4665
                stmt.close();
4666
                commit();
4667
            }
4668
            catch ( SQLException e )
4669
            {
4670
                handleSQLException(e, "");
4671
            }
4672
            finally
4673
            {
4674
                disconnect();
4675
            }
4676
        }
4677
    }
4678
 
4679
    /**  Set RippleStop flag to 'w' for waiting
4680
     *  Indicated that the build system will Ripple the package, when the user confirms that it can be done
4681
     *  Assume database connection has been established
4682
     * @param mRtagId 
4683
     * 
4684
     * @param pkg - Package being processed
4685
     * @throws Exception 
4686
     */
4687
    public void setRippleStopWait(int mRtagId, Package pkg) throws Exception {
4688
 
4689
        // Use a stored procedure as it will also do logging
4690
        mLogger.debug("setRippleStopWait");
4691
        if ( mUseDatabase )
4692
        {
4693
            try
4694
            {
4695
                // "BEGIN  PK_PACKAGE.Set_Ripple_Stop( :PV_ID, :RTAG_ID, :USER_ID, :RSTATE );  END;"
4696
 
4697
                CallableStatement stmt = mConnection.prepareCall( "BEGIN  PK_PACKAGE.Set_Ripple_Stop( ?, ?, ?, 'w' );  END;" );
4698
                stmt.setInt(1, pkg.mId);        // PVID
4699
                stmt.setInt(2, mRtagId);        // RTAG ID 
4700
                stmt.setInt(3, 3768);           // USER ID - buildadm ( Yes I know its ugly )
4701
                stmt.executeUpdate();
4702
                stmt.close();
4703
            }
4704
            catch ( SQLException e )
4705
            {
4706
                handleSQLException(e, "");
4707
            }
4708
        }
4709
 
4710
    }
4711
 
7169 dpurdie 4712
    /** Reset the dumpPlan request
4713
     *  Assume that we have a database connection
7176 dpurdie 4714
     *  @param mRtagId - Identify the target release
4715
     *  @throws Exception 
7169 dpurdie 4716
     */
4717
    public void resetPlanControl(int mRtagId) throws Exception {
4718
        mLogger.debug("resetPlanControl {}", mRtagId);
4719
 
4720
        if ( mUseDatabase )
4721
        {
4722
            try
4723
            {
4724
                CallableStatement stmt = mConnection.prepareCall(
4725
                        "UPDATE release_manager.release_tags SET PLAN_DROP = 'N' WHERE rtag_id  = ?" );
4726
                stmt.setInt(1, mRtagId);
4727
                stmt.executeUpdate();
4728
                stmt.close();
7176 dpurdie 4729
 
4730
                //  Commit only if not covered by the Mutex
4731
                if ( ! mDoNotCommit )
4732
                    commit();
4733
 
7169 dpurdie 4734
            }
4735
            catch ( SQLException e )
4736
            {
4737
                handleSQLException(e, "");
4738
            }
4739
        }
4740
 
7176 dpurdie 4741
        mLogger.debug("resetPlanControl {} Done", mRtagId);        
7169 dpurdie 4742
    }
4743
 
6914 dpurdie 4744
}
4745