Subversion Repositories DevTools

Rev

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