Subversion Repositories DevTools

Rev

Rev 7137 | Rev 7169 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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