• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IQSS / dataverse / #23111

10 Sep 2024 03:14PM CUT coverage: 20.681% (-0.05%) from 20.734%
#23111

Pull #10781

github

landreev
Merge branch 'develop' into 10623-globus-improvements
Resolved conflicts:
	src/main/java/edu/harvard/iq/dataverse/api/Datasets.java
(#10623)
Pull Request #10781: Improved handling of Globus uploads

4 of 417 new or added lines in 15 files covered. (0.96%)

9 existing lines in 3 files now uncovered.

17550 of 84861 relevant lines covered (20.68%)

0.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/edu/harvard/iq/dataverse/timer/DataverseTimerServiceBean.java
1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package edu.harvard.iq.dataverse.timer;
7

8
import edu.harvard.iq.dataverse.DatasetServiceBean;
9
import edu.harvard.iq.dataverse.Dataverse;
10
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
11
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
12
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
13
import edu.harvard.iq.dataverse.harvest.client.HarvestingClient;
14
import edu.harvard.iq.dataverse.harvest.client.HarvestTimerInfo;
15
import edu.harvard.iq.dataverse.harvest.client.HarvesterServiceBean;
16
import edu.harvard.iq.dataverse.harvest.client.HarvestingClientServiceBean;
17
import edu.harvard.iq.dataverse.harvest.server.OAISetServiceBean;
18
import edu.harvard.iq.dataverse.util.SystemConfig;
19
import java.io.IOException;
20
import java.io.Serializable;
21
import java.net.InetAddress;
22
import java.net.UnknownHostException;
23
import java.util.Calendar;
24
import java.util.Date;
25
import java.util.Iterator;
26
import java.util.logging.Level;
27
import java.util.logging.Logger;
28
import jakarta.annotation.PostConstruct;
29
import jakarta.annotation.Resource;
30
import jakarta.ejb.EJB;
31
import jakarta.ejb.Singleton;
32
import jakarta.ejb.Startup;
33
import jakarta.ejb.Timeout;
34
import jakarta.ejb.Timer;
35
import jakarta.ejb.TimerConfig;
36
import jakarta.ejb.TransactionAttribute;
37
import jakarta.ejb.TransactionAttributeType;
38
import jakarta.servlet.http.HttpServletRequest;
39

40

41
/**
42
 * 
43
 * This is a largely intact DVN3 implementation. 
44
 * original
45
 * @author roberttreacy
46
 * ported by 
47
 * @author Leonid Andreev
48
 */
49
//@Stateless
50

51
@Singleton
52
@Startup
53
public class DataverseTimerServiceBean implements Serializable {
×
54
    
55
    private static final Logger logger = Logger.getLogger("edu.harvard.iq.dataverse.timer.DataverseTimerServiceBean");
×
56
    
57
    @Resource
58
    jakarta.ejb.TimerService timerService;
59
    @EJB
60
    HarvesterServiceBean harvesterService;
61
    @EJB
62
    HarvestingClientServiceBean harvestingClientService;
63
    @EJB 
64
    AuthenticationServiceBean authSvc;
65
    @EJB
66
    DatasetServiceBean datasetService;
67
    @EJB
68
    OAISetServiceBean oaiSetService;
69
    @EJB
70
    SystemConfig systemConfig;
71
    
72
    
73
    // The init method that wipes and recreates all the timers on startup
74
    //@PostConstruct
75

76
    @PostConstruct
77
    public void init() {
78
        logger.info("PostConstruct timer check.");
×
79
        
80
        
81
        if (systemConfig.isTimerServer()) {
×
82
            logger.info("I am the dedicated timer server. Initializing mother timer.");
×
83
            
84
            removeAllTimers();
×
85
            // create mother timer:
86
            createMotherTimer();
×
87
            // And the export timer (there is only one)
88
            createExportTimer();
×
89
            
90
        } else {
91
            logger.info("Skipping timer server init (I am not the dedicated timer server)");
×
92
        }
93
    }
×
94
    
95
    public void createTimer(Date initialExpiration, long intervalDuration, Serializable info) {
96
        try {
97
            logger.log(Level.INFO,"Creating timer on " + InetAddress.getLocalHost().getCanonicalHostName());
×
98
        } catch (UnknownHostException ex) {
×
99
            Logger.getLogger(DataverseTimerServiceBean.class.getName()).log(Level.SEVERE, null, ex);
×
100
        }
×
101
        timerService.createIntervalTimer(initialExpiration, intervalDuration, new TimerConfig(info, false));
×
102
    }
×
103

104
    /**
105
     * This method is called whenever an EJB Timer goes off.
106
     * Check to see if this is a Harvest Timer, and if it is
107
     * Run the harvest for the given (scheduled) dataverse
108
     * @param timer
109
     */
110
    @Timeout
111
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
112
    public void handleTimeout(jakarta.ejb.Timer timer) {
113
        // We have to put all the code in a try/catch block because
114
        // if an exception is thrown from this method, Glassfish will automatically
115
        // call the method a second time. (The minimum number of re-tries for a Timer method is 1)
116

117
        if (!systemConfig.isTimerServer()) {
×
118
            //logger.info("I am not the timer server! - bailing out of handleTimeout()");
119
            Logger.getLogger(DataverseTimerServiceBean.class.getName()).log(Level.WARNING, null, "I am not the timer server! - but handleTimeout() got called. Please investigate!");
×
120
        }
121
        
122
        try {
NEW
123
            logger.log(Level.FINE,"Handling timeout on " + InetAddress.getLocalHost().getCanonicalHostName());
×
124
        } catch (UnknownHostException ex) {
×
125
            Logger.getLogger(DataverseTimerServiceBean.class.getName()).log(Level.SEVERE, null, ex);
×
126
        }
×
127
        
128
        if (timer.getInfo() instanceof MotherTimerInfo) {
×
NEW
129
            logger.fine("Behold! I am the Master Timer, king of all timers! I'm here to create all the lesser timers!");
×
130
            removeHarvestTimers();
×
131
            for (HarvestingClient client : harvestingClientService.getAllHarvestingClients()) {
×
132
                createHarvestTimer(client);
×
133
            }
×
134
        } else if (timer.getInfo() instanceof HarvestTimerInfo) {
×
135
            HarvestTimerInfo info = (HarvestTimerInfo) timer.getInfo();
×
136
            try {
137

138
                logger.log(Level.INFO, "running a harvesting client: id=" + info.getHarvestingClientId());
×
139
                // Timer batch jobs are run by the main Admin user. 
140
                // TODO: revisit how we retrieve the superuser here.
141
                // Should it be configurable somewhere, which superuser
142
                // runs these jobs? Should there be a central mechanism for obtaining
143
                // the "major", builtin superuser for this Dataverse instance? 
144
                // -- L.A. 4.5, Aug. 2016
145
                AuthenticatedUser adminUser = authSvc.getAdminUser(); // getAuthenticatedUser("admin");
×
146
                if (adminUser == null) {
×
147
                    logger.info("Scheduled harvest: failed to locate the admin user! Exiting.");
×
148
                    throw new IOException("Scheduled harvest: failed to locate the admin user");
×
149
                } 
150
                logger.info("found admin user "+adminUser.getName());
×
151
                DataverseRequest dataverseRequest = new DataverseRequest(adminUser, (HttpServletRequest)null);
×
152
                harvesterService.doHarvest(dataverseRequest, info.getHarvestingClientId());
×
153

154
            } catch (Throwable e) {
×
155
                // Harvester Service should be handling any error notifications, 
156
                // if/when things go wrong. 
157
                // (TODO: -- verify this logic; harvesterService may still be able 
158
                // to throw an IOException, if it could not run the harvest at all, 
159
                // or could not for whatever reason modify the database record...
160
                // in this case we should, probably, log the error and try to send 
161
                // a mail notification. -- L.A. 4.4)
162
                //dataverseService.setHarvestResult(info.getHarvestingDataverseId(), harvesterService.HARVEST_RESULT_FAILED);
163
                //mailService.sendHarvestErrorNotification(dataverseService.find().getSystemEmail(), dataverseService.find().getName());
164
                logException(e, logger);
×
165
            } 
×
166
        } else if (timer.getInfo() instanceof ExportTimerInfo) {
×
167
            try {
168
                ExportTimerInfo info = (ExportTimerInfo) timer.getInfo();
×
169
                logger.info("Timer Service: Running a scheduled export job.");
×
170
               
171
                // try to export all unexported datasets:
172
                datasetService.exportAll();
×
173
                 // and update all oai sets:
174
                oaiSetService.exportAllSets();
×
175
            } catch (Throwable e) {
×
176
                logException(e, logger);
×
177
            }
×
178
        }
179

180
    }
×
181

182
    public void removeAllTimers() {
183
        logger.info("Removing ALL existing timers.");
×
184

185
        int i = 0;
×
186

187
        for (Iterator it = timerService.getTimers().iterator(); it.hasNext();) {
×
188

189
            Timer timer = (Timer) it.next();
×
190

191
            logger.info("Removing timer " + i + ";");
×
192
            timer.cancel();
×
193

194
            i++;
×
195
        }
×
196
        logger.info("Done!");
×
197
    }
×
198
    
199
    public void removeHarvestTimers() {
200
        // Remove all the harvest timers, if exist: 
201
        //
202
        // (the logging messages below are set to level INFO; it's ok, 
203
        // since this code is only called on startup of the application, 
204
        // and it may be useful to know what existing timers were encountered).
205
        
206
        logger.log(Level.INFO,"Removing existing harvest timers..");
×
207
        
208
        int i = 1; 
×
209
        for (Iterator it = timerService.getTimers().iterator(); it.hasNext();) {
×
210
             
211
            Timer timer = (Timer) it.next();
×
212
            logger.log(Level.INFO, "HarvesterService: checking timer "+i);
×
213
            
214
            if (timer.getInfo() instanceof HarvestTimerInfo) {
×
215
                logger.log(Level.INFO, "HarvesterService: timer "+i+" is a harvesting one; removing.");
×
216
                timer.cancel();
×
217
            }
218
            
219
            i++; 
×
220
        }
×
221
    }
×
222

223
    public void createMotherTimer() {
224
        MotherTimerInfo info = new MotherTimerInfo();
×
225
        Calendar initExpiration = Calendar.getInstance();
×
226
        long intervalDuration = 60 * 60 * 1000; // every hour
×
227
        initExpiration.set(Calendar.MINUTE, 50);
×
228
        initExpiration.set(Calendar.SECOND, 0);
×
229
        
230
        Date initExpirationDate = initExpiration.getTime();
×
231
        Date currTime = new Date();
×
232
        if (initExpirationDate.before(currTime)) {
×
233
            initExpirationDate.setTime(initExpiration.getTimeInMillis() + intervalDuration);
×
234
        }
235
        
236
        logger.info("Setting the \"Mother Timer\", initial expiration: " + initExpirationDate);
×
237
        createTimer(initExpirationDate, intervalDuration, info);
×
238
    }
×
239
    
240
    public void createHarvestTimer(HarvestingClient harvestingClient) {       
241
        
242
        if (harvestingClient.isScheduled()) {
×
243
            long intervalDuration = 0;
×
244
            Calendar initExpiration = Calendar.getInstance();
×
245
            initExpiration.set(Calendar.MINUTE, 0);
×
246
            initExpiration.set(Calendar.SECOND, 0);
×
247
            if (harvestingClient.getSchedulePeriod().equals(HarvestingClient.SCHEDULE_PERIOD_DAILY)) {
×
248
                intervalDuration = 1000 * 60 * 60 * 24;
×
249
                initExpiration.set(Calendar.HOUR_OF_DAY, harvestingClient.getScheduleHourOfDay());
×
250

251
            } else if (harvestingClient.getSchedulePeriod().equals(harvestingClient.SCHEDULE_PERIOD_WEEKLY)) {
×
252
                intervalDuration = 1000 * 60 * 60 * 24 * 7;
×
253
                initExpiration.set(Calendar.HOUR_OF_DAY, harvestingClient.getScheduleHourOfDay());
×
254
                initExpiration.set(Calendar.DAY_OF_WEEK, harvestingClient.getScheduleDayOfWeek() + 1); //(saved as zero-based array but Calendar is one-based.)
×
255
  
256
            } else {
257
                logger.log(Level.WARNING, "Could not set timer for harvesting client id=" + harvestingClient.getId() + ", unknown schedule period: " + harvestingClient.getSchedulePeriod());
×
258
                return;
×
259
            }
260
            Date initExpirationDate = initExpiration.getTime();
×
261
            Date currTime = new Date();
×
262
            if (initExpirationDate.before(currTime)) {
×
263
                initExpirationDate.setTime(initExpiration.getTimeInMillis() + intervalDuration);
×
264
            }
265
            logger.log(Level.INFO, "Setting timer for harvesting client " + harvestingClient.getName() + ", initial expiration: " + initExpirationDate);
×
266
            createTimer(initExpirationDate, intervalDuration, new HarvestTimerInfo(harvestingClient.getId(), harvestingClient.getName(), harvestingClient.getSchedulePeriod(), harvestingClient.getScheduleHourOfDay(), harvestingClient.getScheduleDayOfWeek()));
×
267
        }
268
    }
×
269

270
    public void updateHarvestTimer(HarvestingClient harvestingClient) {
271
        removeHarvestTimer(harvestingClient);
×
272
        createHarvestTimer(harvestingClient);
×
273
    }
×
274

275
    
276
    public void removeHarvestTimer(HarvestingClient harvestingClient) {
277
         // Clear dataverse timer, if one exists
278
        try {
279
            logger.log(Level.INFO,"Removing harvest timer on " + InetAddress.getLocalHost().getCanonicalHostName());
×
280
        } catch (UnknownHostException ex) {
×
281
            Logger.getLogger(DataverseTimerServiceBean.class.getName()).log(Level.SEVERE, null, ex);
×
282
        }
×
283
        for (Iterator it = timerService.getTimers().iterator(); it.hasNext();) {
×
284
            Timer timer = (Timer) it.next();
×
285
            if (timer.getInfo() instanceof HarvestTimerInfo) {
×
286
                HarvestTimerInfo info = (HarvestTimerInfo) timer.getInfo();
×
287
                if (info.getHarvestingClientId().equals(harvestingClient.getId())) {
×
288
                    timer.cancel();
×
289
                }
290
            }
291
        }
×
292
    }
×
293

294
    public void createExportTimer() {
295
        ExportTimerInfo info = new ExportTimerInfo();
×
296
        Calendar initExpiration = Calendar.getInstance();
×
297
        long intervalDuration = 24 * 60 * 60 * 1000; // every day
×
298
        initExpiration.set(Calendar.MINUTE, 0);
×
299
        initExpiration.set(Calendar.SECOND, 0);
×
300
        initExpiration.set(Calendar.HOUR_OF_DAY, 2); // 2AM, fixed.
×
301
        
302
        
303
        Date initExpirationDate = initExpiration.getTime();
×
304
        Date currTime = new Date();
×
305
        if (initExpirationDate.before(currTime)) {
×
306
            initExpirationDate.setTime(initExpiration.getTimeInMillis() + intervalDuration);
×
307
        }
308
        
309
        logger.info("Setting the Export Timer, initial expiration: " + initExpirationDate);
×
310
        createTimer(initExpirationDate, intervalDuration, info);
×
311
    }
×
312

313
    public void createExportTimer(Dataverse dataverse) {
314
         /* Not yet implemented. The DVN 3 implementation can be used as a model */
315

316
    }
×
317

318
     public void removeExportTimer() {
319
         /* Not yet implemented. The DVN 3 implementation can be used as a model */
320
    }
×
321

322
    /* Utility methods: */ 
323
    private void logException(Throwable e, Logger logger) {
324

325
        boolean cause = false;
×
326
        String fullMessage = "";
×
327
        do {
328
            String message = e.getClass().getName() + " " + e.getMessage();
×
329
            if (cause) {
×
330
                message = "\nCaused By Exception.................... " + e.getClass().getName() + " " + e.getMessage();
×
331
            }
332
            StackTraceElement[] ste = e.getStackTrace();
×
333
            message += "\nStackTrace: \n";
×
334
            for (int m = 0; m < ste.length; m++) {
×
335
                message += ste[m].toString() + "\n";
×
336
            }
337
            fullMessage += message;
×
338
            cause = true;
×
339
        } while ((e = e.getCause()) != null);
×
340
        logger.severe(fullMessage);
×
341
    }
×
342
    
343
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc