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.helpers;
19  
20  import java.text.MessageFormat;
21  import java.util.concurrent.locks.ReadWriteLock;
22  import java.util.concurrent.locks.ReentrantReadWriteLock;
23  import org.apache.log4j.Logger;
24  import org.w3c.dom.Document;
25  import at.ac.tuwien.infosys.sm4all.copal.api.ContextEventType;
26  import at.ac.tuwien.infosys.sm4all.copal.api.ContextPublisher;
27  import at.ac.tuwien.infosys.sm4all.copal.api.MalformedDocumentException;
28  import at.ac.tuwien.infosys.sm4all.copal.api.event.xml.XMLContextEvent;
29  import at.ac.tuwien.infosys.sm4all.copal.api.event.xml.XMLContextEventType;
30  import at.ac.tuwien.infosys.sm4all.copal.service.event.EventPublisher;
31  
32  /**
33   * Helper class for implementing {@link ContextPublisher}s.
34   * 
35   * @author sanjin
36   */
37  public abstract class AbstractContextPublisher implements ContextPublisher {
38  
39      private static final Logger LOGGER = Logger.getLogger(AbstractContextPublisher.class);
40  
41      private final ReadWriteLock lock = new ReentrantReadWriteLock();
42      private final String sourceID;
43      private final String eventTypeName;
44      private EventPublisher eventPublisher;
45      private XMLContextEventType eventType;
46      private boolean started = false;
47  
48      /**
49       * Use specified source ID and given event type as return values for
50       * {@link #getSourceID()} and {@link #getType()} methods respectively.
51       * 
52       * @param sourceID the source ID of context publisher.
53       * @param type the name of {@link ContextEventType} for published events.
54       */
55      protected AbstractContextPublisher(final String sourceID, final String type) {
56          this.sourceID = sourceID;
57          this.eventTypeName = type;
58      }
59  
60      /**
61       * This method is called when {@link EventPublisher} becomes available for
62       * publishing events of the specified {@link XMLContextEventType}. This
63       * method should be implemented by specific publishers and should be used as
64       * a notification that publisher can, from now on, publish events.
65       * 
66       * @param type the {@link XMLContextEventType} of published events.
67       */
68      protected abstract boolean start(XMLContextEventType type);
69  
70      /**
71       * This method is called when {@link EventPublisher} becomes unavailable for
72       * publishing events of the specified {@link XMLContextEventType}. This
73       * method should be implemented by specific publishers and should be used as
74       * a notification that publisher should not publish any more events.
75       * 
76       * @param type the {@link XMLContextEventType} of published events.
77       */
78      protected abstract void stop(XMLContextEventType type);
79  
80      @Override
81      public final String getSourceID() {
82          return this.sourceID;
83      }
84  
85      @Override
86      public final String getEventType() {
87          return this.eventTypeName;
88      }
89  
90      /**
91       * Returns if this {@link AbstractContextPublisher} is started and can start
92       * publish events.
93       * 
94       * @return if this {@link AbstractContextPublisher} is started and can start
95       *         publish events.
96       */
97      public boolean isStarted() {
98          return this.started;
99      }
100 
101     @Override
102     public boolean start(final EventPublisher publisher,
103             final XMLContextEventType type) {
104         if (LOGGER.isDebugEnabled())
105             LOGGER.debug(MessageFormat.format("Starting publisher ''{0}''.",
106                     this.sourceID));
107         boolean result = false;
108 
109         this.lock.writeLock().lock();
110         try {
111             if (!this.started) {
112                 this.eventPublisher = publisher;
113                 this.eventType = type;
114 
115                 if (start(this.eventType)) {
116                     this.started = true;
117                     result = true;
118 
119                     if (LOGGER.isInfoEnabled())
120                         LOGGER.info(MessageFormat.format(
121                                 "Successfully started publisher ''{0}''!",
122                                 this.sourceID));
123                 } else {
124                     this.eventPublisher = null;
125                     this.eventType = null;
126 
127                     LOGGER.error(MessageFormat.format(
128                             "Publisher ''{0}'' could not be started!",
129                             this.sourceID));
130                 }
131             }
132         } finally {
133             this.lock.writeLock().unlock();
134         }
135 
136         return result;
137     }
138 
139     @Override
140     public final void stop(final EventPublisher publisher,
141             final XMLContextEventType type) {
142         if (LOGGER.isDebugEnabled())
143             LOGGER.debug(MessageFormat.format("Stopping publisher ''{0}''.",
144                     this.sourceID));
145 
146         this.lock.writeLock().lock();
147         try {
148             if (this.started) {
149                 if ((this.eventPublisher.equals(publisher))
150                         && (this.eventType.equals(type))) {
151                     stop(type);
152                     this.eventType = null;
153                     this.eventPublisher = null;
154                     this.started = false;
155 
156                     if (LOGGER.isInfoEnabled())
157                         LOGGER.info(MessageFormat.format(
158                                 "Successfully stopped publisher ''{0}''!",
159                                 this.sourceID));
160                 } else
161                     LOGGER.warn(MessageFormat.format(
162                             "Publisher ''{0}'' was not started for specified event publisher and event type! Ignoring",
163                             this.sourceID));
164             } else
165                 LOGGER.warn(MessageFormat.format(
166                         "Publisher ''{0}'' was never started! Ignoring",
167                         this.sourceID));
168         } finally {
169             this.lock.writeLock().unlock();
170         }
171     }
172 
173     /**
174      * Publish specified {@link Document} as an event.
175      * 
176      * @param document the {@link Document} to be published.
177      * @return <code>true</code>> if publishing was successful;
178      *         <code>false</code> otherwise.
179      * @throws MalformedDocumentException if specified {@link Document} is
180      *         malformed for published {@link ContextEventType}.
181      */
182     protected final boolean publish(final Document document)
183             throws MalformedDocumentException {
184         return publish(new XMLContextEvent(this.eventType, this.sourceID,
185                 document));
186     }
187 
188     /**
189      * Publish given {@link XMLContextEvent}.
190      * 
191      * @param event the {@link XMLContextEvent} to be published.
192      * @return <code>true</code>> if publishing was successful;
193      *         <code>false</code> otherwise.
194      */
195     protected final boolean publish(final XMLContextEvent event) {
196         boolean result = false;
197 
198         this.lock.readLock().lock();
199         try {
200             if (this.started) {
201                 if (this.eventType.equals(event.getType())) {
202                     result = this.eventPublisher.publish(event);
203 
204                     if (result) {
205                         if (LOGGER.isInfoEnabled())
206                             LOGGER.info(MessageFormat.format(
207                                     "Successfully sent event from ''{0}''!",
208                                     this.sourceID));
209                     } else
210                         LOGGER.error(MessageFormat.format(
211                                 "Failed to send event from ''{0}''!",
212                                 this.sourceID));
213                 } else
214                     LOGGER.error(MessageFormat.format(
215                             "Failed to send event from ''{0}''! Publisher not register to publish ''{1}'' events.",
216                             this.sourceID, event.getType().getName()));
217             } else
218                 LOGGER.error(MessageFormat.format(
219                         "Failed to send event from ''{0}''! Publisher not registered.",
220                         this.sourceID));
221         } finally {
222             this.lock.readLock().unlock();
223         }
224 
225         return result;
226     }
227 }