View Javadoc

1   /* This file is part of COPAL (COntext Provisioning for All).
2    *
3    * COPAL is a part of SM4All (Smart hoMes for All) project.
4    *
5    * COPAL is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * COPAL 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
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with COPAL. If not, see <http://www.gnu.org/licenses/>.
17   */
18  package at.ac.tuwien.infosys.sm4all.copal.api.publisher;
19  
20  import java.text.MessageFormat;
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Timer;
24  import java.util.TimerTask;
25  import java.util.concurrent.locks.ReadWriteLock;
26  import java.util.concurrent.locks.ReentrantReadWriteLock;
27  import org.apache.log4j.Level;
28  import org.apache.log4j.Logger;
29  import at.ac.tuwien.infosys.sm4all.copal.api.ContextException;
30  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
31  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEventType;
32  
33  /**
34   * Implementation of {@link ContextPublisher} that polls periodically for a
35   * {@link ContextEvent}s.
36   * 
37   * @author sanjin
38   */
39  public abstract class PolledPublisher extends BasePublisher {
40  
41      private static final Logger LOGGER = Logger.getLogger(PolledPublisher.class);
42  
43      private final ReadWriteLock lock = new ReentrantReadWriteLock();
44      private final Map<String, Timer> timers = new HashMap<String, Timer>();
45      private final long interval;
46  
47      /**
48       * Creates instance of polled {@link ContextPublisher} that has specified
49       * source ID and polls specified {@link ContextEvent} types at specified
50       * interval.
51       * 
52       * @param interval the poll interval.
53       * @param sourceID the source ID.
54       * @param polledTypes polled {@link ContextEvent} types.
55       */
56      protected PolledPublisher(final long interval, final String sourceID,
57              final String... polledTypes) {
58          super(sourceID, polledTypes);
59  
60          this.interval = interval;
61      }
62  
63      /**
64       * This method is polled periodically (defined with poll interval in the
65       * {@link PolledPublisher#PolledPublisher(long, String, String...)}
66       * constructor) to produce a {@link ContextEvent} of specified
67       * {@link ContextEventType} that will be published.
68       * 
69       * @param eventType the type of polled {@link ContextEvent}.
70       * @return the {@link ContextEvent}
71       * @throws ContextException if polling fails.
72       */
73      protected abstract ContextEvent poll(ContextEventType eventType)
74              throws ContextException;
75  
76      @Override
77      protected boolean start(final ContextEventType eventType) {
78          this.lock.writeLock().lock();
79          try {
80              final String eventTypeName = eventType.getName();
81              if (!this.timers.containsKey(eventTypeName)) {
82                  final Timer timer = new Timer();
83                  timer.schedule(new Poll(eventType), 0, this.interval);
84                  this.timers.put(eventTypeName, timer);
85              }
86          } finally {
87              this.lock.writeLock().unlock();
88          }
89  
90          return true;
91      }
92  
93      @Override
94      protected void stop(final ContextEventType eventType) {
95          this.lock.writeLock().lock();
96          try {
97              for (final Timer timer : this.timers.values()) {
98                  timer.cancel();
99              }
100 
101             this.timers.clear();
102         } finally {
103             this.lock.writeLock().unlock();
104         }
105     }
106 
107     private class Poll extends TimerTask {
108 
109         private final ContextEventType eventType;
110 
111         /**
112          * Create {@link Poll} {@link TimerTask} that polls for
113          * {@link ContextEvent}s of specified {@link ContextEventType}.
114          * 
115          * @param eventType the {@link ContextEventType} of polled
116          *        {@link ContextEvent}s.
117          */
118         protected Poll(final ContextEventType eventType) {
119             super();
120 
121             this.eventType = eventType;
122         }
123 
124         @SuppressWarnings("synthetic-access")
125         @Override
126         public void run() {
127             PolledPublisher.this.lock.readLock().lock();
128             try {
129                 final ContextEvent event = poll(this.eventType);
130                 if (null != event) {
131                     publish(event);
132                     if (LOGGER.isInfoEnabled()) {
133                         LOGGER.info(MessageFormat.format(
134                                 "Event ''{0}'' published.",
135                                 this.eventType.getName()));
136                     }
137                 }
138             } catch (final ContextException ex) {
139                 if (LOGGER.isEnabledFor(Level.ERROR)) {
140                     LOGGER.error(MessageFormat.format(
141                             "Could not publish event ''{0}''!",
142                             this.eventType.getName()), ex);
143                 }
144             } finally {
145                 PolledPublisher.this.lock.readLock().unlock();
146             }
147         }
148     }
149 }