Subversion Repositories DevTools

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6914 dpurdie 1
package com.erggroup.buildtool.daemon;
2
 
3
import com.erggroup.buildtool.abt.BuildToolException;
4
import com.erggroup.buildtool.daemon.BuildThread;
5
import com.erggroup.buildtool.ripple.Package;
6
import com.erggroup.buildtool.ripple.ReleaseManager;
7
import com.erggroup.buildtool.ripple.RippleEngine;
8
import com.erggroup.buildtool.ripple.RunLevel.BuildState;
9
import com.erggroup.buildtool.utilities.MutableDate;
10
 
11
import java.sql.SQLException;
12
 
13
import org.apache.log4j.Logger;
14
 
15
/**
16
 * Slave Thread sub component
17
 */
18
public class SlaveThread extends BuildThread
19
{
20
 
21
    /**
22
     * Logger
23
     * 
24
     * @attribute
25
     */
26
    private static final Logger mLogger = Logger.getLogger(SlaveThread.class);
27
 
28
    /** Holds the buildFile content
29
     * 
30
     */
31
    protected String mBuildFileContent = null;
32
 
33
    /**constructor
34
     * @param rtagId          - Identifies the Release
35
     * @param rconId          - Identifies the Controlling entry
36
     * @param releaseManager  - A ReleaseManager entry to use
37
     * @param unitTest        - Unit Test data 
38
     */
39
    public SlaveThread(int rtagId, int rconId, ReleaseManager releaseManager, String unitTest)
40
    {
41
        super(rtagId, rconId, releaseManager, unitTest);
42
        mLogger.warn("SlaveThread rtag_id " + rtagId + " rcon_id " + rconId);
43
    }
44
 
45
    /**
46
     * implements the sequence diagrams consume build files, allowed to proceed,
47
     * check environment
48
     */
49
    public void run()
50
    {
51
        Integer id = Integer.valueOf(mRtagId);
52
        setName(id.toString());
53
        mLogger.warn("run");
54
        boolean exit = false;
55
        mRippleEngine = new RippleEngine(mReleaseManager, mRtagId, true);
56
 
57
        while (!exit)
58
        {
59
            try
60
            {
61
                mLogger.fatal("run calling sleepCheck");
62
                mPhase.setPhase("sleepCheck");
63
                sleepCheck();
64
 
65
                mLogger.fatal("run calling rippleEngine.collectMetaData");
66
                mPhase.setPhase("collectMetaData");
67
                mRippleEngine.collectMetaData();
68
 
69
                if (Thread.currentThread().isInterrupted())
70
                {
71
                    mLogger.warn("run is interrupted");
72
                    // unit test technique
73
                    throw new ExitException();
74
                }
75
 
76
                if (mUnitTest.compareTo("unit test spawn thread") == 0)
77
                {
78
                    throw new Exception();
79
                }
80
 
81
                // allowed to proceed
82
                if (mUnitTest.compareTo("unit test consume build files") != 0)
83
                {
84
                    mLogger.fatal("run calling allowedToProceed");
85
                    mPhase.setPhase("allowedToProceed");
86
                    allowedToProceed(false);
87
                    mLogger.info("run allowedToProceed returned");
88
                }
89
 
90
                // Indicate that the Slave is WAITING - for a job
91
                mPhase.setPhase("Waiting for work");
92
                mLogger.fatal("run changing run level to WAITING for rcon_id " + mRconId);
93
 
94
 
95
                // Wait for Slave to be set as Active
96
                while (!BuildDaemon.mShutDown)
97
                {
98
                    // Periodically indicate, to Release Manager, that the slave is still alive
99
                    // A warning will be raised after 10 minutes, so it must be less than that
100
                    mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_WAITING);
101
 
102
                    //
103
                    //  Wait to be notified that a build request is present
104
                    //  Have a timeout just to be sure to be sure
105
                    //
106
                    if (mUnitTest.length() == 0) {
107
                        synchronized (mActiveBuildMonitor) {
108
                            try {
109
                                mActiveBuildMonitor.wait(120 * 1000L);
110
                            }
111
                            catch ( InterruptedException e  ) {
112
                                Thread.currentThread().interrupt();
113
                                mLogger.error("InterruptedException in Wait for Active Build");
114
                            }
115
                        }
116
                    }
117
 
118
                    //
119
                    //  Determine if the build cycle can proceed
120
                    //      May be a shutdown request
121
                    //      May be no longer configured
122
                    //      May be stopped
123
                    //      May be paused
124
                    //      May be indefinite pause
125
                    //  Will throw exception if we shouldn't continue on this cycle
126
                    //  
127
                    mLogger.info("run allowedToContinue");
128
                    allowedToContinue(false);
129
 
130
                    // Detect build Request
131
                    //  A non-null buildfile published in the database
132
                    mLogger.info("run calling mReleaseManager.queryBuildFile");
133
                    mBuildFileContent =  mReleaseManager.queryBuildFile(mRconId);
134
                    if (mBuildFileContent != null )
135
                    {
136
                        // Build request detected
137
                        mRunLevel.persist(mReleaseManager, mRconId, BuildState.DB_ACTIVE);
138
                        break;
139
                    }
140
 
141
                }
142
 
143
                //
144
                //  Build Request detected
145
                //      Buildfile has been extracted from the database, but not yet saved
146
                //
147
                if (BuildDaemon.mShutDown)
148
                {
149
                    mLogger.warn("Slave run ShutDown requested");
150
                    throw new ExitException();
151
                }
152
 
153
                mLogger.info("run consumed build files");
154
                if (mUnitTest.compareTo("unit test consume build files") == 0)
155
                {
156
                    throw new ExitException();
157
                }
158
 
159
                // set CURRENT_BUILD_FILES to null
160
                //  Indicates that we have taken the file and will prevent multiple builds
161
                mLogger.info("run calling mReleaseManager.clearBuildFile");
162
                mPhase.setPhase("clearBuildFile");
163
                mReleaseManager.clearBuildFile(mRconId);
164
 
165
                // check environment
166
                mLogger.warn("run checkEnvironment");
167
                mPhase.setPhase("checkEnvironment");
168
                checkEnvironment();
169
                mLogger.info("run checkEnvironment returned");
170
 
171
                mLastBuildWasBenign = true;
172
                if (mBuildFileContent.compareTo(mDummyBuildFileContent) != 0)
173
                {
174
                    mLastBuildWasBenign = false;
175
 
176
                    // Start of a build cycle. Set new log file to capture
177
                    // entire build log
178
                    mPhase.setPhase("flagStartBuildCycle");
179
                    flagStartBuildCycle();
180
                    mReporting.resetData();
181
 
182
                    mLogger.fatal("Collect fresh MetaData");
183
                    mPhase.setPhase("collectMetaData");
184
                    mRippleEngine.collectMetaData();
185
 
186
                    // Save the build file
187
                    mLogger.fatal("Save buildfile");
188
                    mPhase.setPhase("Save buildfile");
189
                    saveBuildFile(mBuildFileContent);
190
 
191
                    // deliver change to product baseline
192
                    mLogger.fatal("run calling setViewUp");
193
                    mPhase.setPhase("Setup View for build");
194
                    deliverChange("AbtSetUp", true, true);
195
 
196
                    mLogger.fatal("run calling deliverChange - the actual build");
197
                    mPhase.setPhase("deliverChange for Build");
198
                    deliverChange(null, true, false);
199
 
200
                    mLogger.fatal("run calling deliverChange on AbtTearDown");
201
                    mPhase.setPhase("AbtTearDown");
202
                    deliverChange("AbtTearDown", false, true);
203
 
204
                    if (mReporting.buildFailureLogFile != null)
205
                    {
206
                        mLogger.fatal("run calling excludeFromBuild");
207
                        mPhase.setPhase("excludeFromBuild");
208
                        mReleaseManager.excludeFromBuild(false, 
209
                                                         mReporting.packageVersionId,
210
                                                         mReporting.packageVersion, 
211
                                                         mRtagId, 
212
                                                         null, 
213
                                                         null, 
214
                                                         mReporting.buildFailureLogFile,
215
                                                         false, mReporting.isaTestBuild);
216
                    }
217
 
218
                    mLogger.info("run deliverChange returned");
219
                    mPhase.setPhase("End of Build Cycle");
220
                }
221
                mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
222
            } 
223
            //---------------------------------------------------------------
224
            //    Build loop exception handling (only)
225
            //
226
            catch (ShouldNotContinueExpection e)
227
            {
228
                mLogger.fatal("ShouldNotContinueExpection:" + e.getMessage());
229
            }
230
            catch (SQLException e)
231
            {
232
                // oracle connection issues
233
                //  Request a prolonged sleep at the start of the build loop
234
                mLogger.fatal("run oracle connection issues");
235
                mException = true;
236
            } 
237
            catch (ExitException e)
238
            {
239
                mLogger.warn("run ExitException");
240
                exit = true;
241
            } 
242
            catch (InterruptedException e)
243
            {
244
                mLogger.warn("run InterruptedException");
245
                Thread.currentThread().interrupt();
246
            }
247
            catch (BuildSystemException e) {
248
                // BuildSystem exception - a (possibly) correctable error
249
                // Flag as recoverable
250
                //    - Can't create XML build file
251
                //    - 
252
                // 
253
                mLogger.fatal("run BuildSystemException");
254
                mPhase.setPhase("BuildSystemException indefinitePause");
255
                notifyIndefinitePause(e.getMessage());
256
                mReleaseManager.indefinitePause(false);
257
                mException = true;
258
                mRecoverable = true;
259
 
260
            }
261
            catch( BuildToolException e)
262
            {
263
                // Buildtool exception - an uncorrectable error
264
                //    - Can't parse XML build file
265
                //    - 
266
                // 
267
                mLogger.fatal("run BuildToolException");
268
                mPhase.setPhase("BuildToolException indefinitePause");
269
                notifyIndefinitePause(e.getMessage());
270
                mReleaseManager.indefinitePause(false);
271
                mException = true;
272
            }
273
            catch (Exception e)
274
            {
275
	        //  Uncaptured exception
276
	        //  These are not good. Current mechanism to handle this condition is:
277
	        //      1) Email build system administrator
278
	        //      2) Pause the build system
279
	        //  
280
                mLogger.error("run indefinitePause " + e.toString());
281
 
282
                // DEVI 51366 force sleep at beginning of while loop
283
                mException = true;
284
 
285
                String cause = e.getMessage();
286
                if ( cause == null || cause.compareTo("null") == 0 )
287
                {
288
                  cause = "Internal Error: " + e.toString();
289
                }
290
 
291
                try
292
                {
293
                    // notify first
294
                    // many reasons for indefinite pause, including database related, so do database last
295
                    mRecoverable = false;
296
 
297
                    if (cause.compareTo(Package.mRecoverable) == 0)
298
                    {
299
                        mRecoverable = true;
300
                    }
301
 
302
                    mPhase.setPhase("Notify indefinitePause");
303
                    notifyIndefinitePause(cause);
304
                    mReleaseManager.indefinitePause(mRecoverable);
305
        	}
306
        	catch( Exception f )
307
                {
308
                    mLogger.error("run indefinitePause failed");
309
                }
310
            }
311
        }
312
        try {
313
            mReleaseManager.clearCurrentPackageBeingBuilt(mRconId);
314
        } catch (Exception e) {
315
            mLogger.error("Exception in clearCurrentPackageBeingBuilt:" + e.getMessage());
316
        }
317
        mPhase.setPhase("Exit Thread");
318
    }
319
 
320
    /** Determine if we are allowed to continue in this build cycle
321
     *      May be no longer configured
322
     *      May be stopped
323
     *      May be paused
324
     *      May be indefinite pause
325
     *  Will throw exceptions if we shouldn't continue on this cycle
326
     *  Does not hang around waiting for condition to clear - thats done elsewhere
327
     *  
328
     * @param master - is a master machine making this call
329
     * @throws ExitException 
330
     * @throws ShouldNotContinueExpection 
331
     * @throws SQLException 
332
     */
333
    private void allowedToContinue(boolean master) throws ExitException, ShouldNotContinueExpection, SQLException, Exception {
334
 
335
        if (BuildDaemon.mShutDown)
336
        {
337
            mLogger.warn("allowedToContinue. ShutDown requested");
338
            throw new ExitException();
339
        }
340
 
341
        try
342
        {
343
            mLogger.fatal("allowedToContinue calling mReleaseManager.connect");                      
344
            mReleaseManager.connect();
345
 
346
            //  Ensure that the machine is a part of the current build set
347
            mLogger.fatal("allowedToContinue calling mReleaseManager.queryReleaseConfig");                      
348
            if ( !mReleaseManager.queryReleaseConfig(mRtagId, mRconId, BuildDaemon.mHostname, getMode(), mStartTime) )
349
            {
350
                mLogger.warn("allowedToContinue queryReleaseConfig failed");
351
                mReleaseManager.disconnect();
352
                throw new ExitException();
353
            }
354
 
355
 
356
            //  Check for scheduled downtime or indefinite pause
357
            MutableDate resumeTime = new MutableDate();
358
            mLogger.fatal("allowedToContinue calling mReleaseManager.queryRunLevelSchedule");                      
359
            if ( !mReleaseManager.queryRunLevelSchedule(resumeTime) )
360
            {
361
              mLogger.info("allowedToContinue scheduled downtime");
362
              mReleaseManager.disconnect();
363
              throw new ShouldNotContinueExpection("Scheduled downtime");
364
            }
365
 
366
            //
367
            //  If commanded to pause, then wait around until the command has been removed.
368
            //
369
            mLogger.fatal("allowedToContinue calling mReleaseManager.queryDirectedRunLevel");                      
370
            if ( !mReleaseManager.queryDirectedRunLevel(mRconId) )
371
            {
372
                mLogger.fatal("allowedToContinue Pause Detected");
373
                throw new ShouldNotContinueExpection("Pause Detected");
374
            }
375
 
376
        }
377
        finally
378
        {
379
          // this block is executed regardless of what happens in the try block
380
          // even if an exception is thrown
381
          // ensure disconnect
382
          mLogger.fatal("allowedToContinue calling mReleaseManager.disconnect");                      
383
          mReleaseManager.disconnect();
384
        }
385
 
386
        // One last test for a shut down request
387
        if (BuildDaemon.mShutDown)
388
        {
389
            mLogger.warn("allowedToContinue. ShutDown requested");
390
            throw new ExitException();
391
        }
392
 
393
    }
394
 
395
    /**
396
     * returns 'S'
397
     */
398
    protected char getMode()
399
    {
400
        mLogger.debug("getMode");
401
        return 'S';
402
    }
403
}