1 /*
2 * Copyright (C) 2007 ETH Zurich
3 *
4 * This file is part of Fosstrak (www.fosstrak.org).
5 *
6 * Fosstrak is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License version 2.1, as published by the Free Software Foundation.
9 *
10 * Fosstrak is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with Fosstrak; if not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
19 */
20
21 package org.fosstrak.epcis.repository.query;
22
23 import java.io.Serializable;
24 import java.util.Calendar;
25 import java.util.Date;
26
27 import javax.management.Notification;
28 import javax.management.NotificationListener;
29 import javax.management.timer.Timer;
30
31 import org.fosstrak.epcis.model.ImplementationException;
32 import org.fosstrak.epcis.model.QueryParams;
33 import org.fosstrak.epcis.soap.ImplementationExceptionResponse;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38 * Special case of Subscription (from subscribe() on query interface) where the
39 * subscription is scheduled.
40 *
41 * @author Alain Remund
42 * @author Arthur van Dorp
43 */
44 public class QuerySubscriptionScheduled extends QuerySubscription implements NotificationListener, Serializable {
45
46 private static final long serialVersionUID = -5073503857856387167L;
47
48 private static final Log LOG = LogFactory.getLog(QuerySubscriptionScheduled.class);
49
50 /**
51 * Schedule indicating when subscription query is to be executed.
52 */
53 protected Schedule schedule;
54
55 /**
56 * Whether to continue with sending results.
57 */
58 protected Boolean doItAgain = Boolean.TRUE;
59
60 /**
61 * Constructor to be used when recreating from storage.
62 *
63 * @param subscriptionID
64 * The subscription ID.
65 * @param queryParams
66 * Query parameters.
67 * @param dest
68 * The destination URI.
69 * @param reportIfEmpty
70 * Whether to report when nothing changed.
71 * @param initialRecordTime
72 * The initial record time.
73 * @param lastTimeExecuted
74 * The last time the query was executed.
75 * @param schedule
76 * The query Schedule.
77 * @param queryName
78 * The query name.
79 * @throws ImplementationException
80 * If the Scheduler could not be started.
81 */
82 public QuerySubscriptionScheduled(final String subscriptionID, final QueryParams queryParams, final String dest,
83 final Boolean reportIfEmpty, final Calendar initialRecordTime,
84 final Calendar lastTimeExecuted, final Schedule schedule, final String queryName)
85 throws ImplementationExceptionResponse {
86 super(subscriptionID, queryParams, dest, reportIfEmpty, initialRecordTime, lastTimeExecuted, queryName);
87 this.schedule = schedule;
88 if (LOG.isDebugEnabled()) {
89 Date nextSchedule = schedule.nextScheduledTime().getTime();
90 LOG.debug("Next scheduled time for the subscribed query is '" + nextSchedule + "'.");
91 LOG.debug("URI to which to send results for the subscribed query is " + dest.toString());
92 }
93 startThread();
94 }
95
96 /**
97 * Starts a Timer to get this query executed in specific time intervals.
98 *
99 * @throws ImplementationException
100 * If the next scheduled date cannot be evaluated.
101 */
102 private void startThread() throws ImplementationExceptionResponse {
103 Timer nextAction = new Timer();
104 nextAction.addNotificationListener(this, null, nextAction);
105
106 Date nextSchedule = schedule.nextScheduledTime().getTime();
107 nextAction.addNotification("SubscriptionSchedule", "Please do the query", null, nextSchedule);
108 nextAction.start();
109 }
110
111 /**
112 * Stops the re-execution of the schedule. This method is called when a
113 * subscribed query get's unsubscribed.
114 */
115 public void stopSubscription() {
116 doItAgain = Boolean.FALSE;
117 }
118
119 /**
120 * The Object has definitely been destroyed. This may take a while.
121 */
122 protected void finalize() {
123 LOG.debug("A subscribed query has been garbage collected.");
124 }
125
126 /**
127 * This method is handles a notification when the Timer for the schedule
128 * times out.
129 *
130 * @see javax.management.NotificationListener#handleNotification(javax.management.Notification,
131 * java.lang.Object)
132 * @param pNotification
133 * The Notification.
134 * @param pHandback
135 * A Timer stating the time when the Notification should be
136 * invoked.
137 */
138 public void handleNotification(final Notification pNotification, final Object pHandback) {
139 if (pHandback == null) {
140 LOG.error("The timer stating the next scheduled query execution time is null!");
141 return;
142 }
143 Timer timer = (Timer) pHandback;
144
145 if (!doItAgain.booleanValue()) {
146 timer.stop();
147 } else {
148 // execute the query and determine next scheduled execution time
149 executeQuery();
150 setNextScheduledExecutionTime(timer);
151 }
152 }
153
154 /**
155 * Determines the next scheduled execution time for this subscribed query.
156 *
157 * @param timer
158 * The Timer to set the next scheduled time.
159 * @throws IllegalArgumentException
160 */
161 protected void setNextScheduledExecutionTime(final Timer timer) throws IllegalArgumentException {
162 try {
163 Date nextSchedule = schedule.nextScheduledTime().getTime();
164 LOG.debug("Next scheduled time for the subscribed query is '" + nextSchedule + "'.");
165 timer.addNotification("SubscriptionSchedule", "Please do the query", timer, nextSchedule);
166 } catch (ImplementationExceptionResponse e) {
167 String msg = "The next scheduled date for the subscribed query with ID '" + getSubscriptionID()
168 + "' cannot be evaluated: " + e.getMessage();
169 LOG.error(msg, e);
170 }
171 }
172
173 }