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.processor;
19  
20  import java.text.MessageFormat;
21  import java.util.Arrays;
22  import java.util.HashSet;
23  import java.util.Set;
24  import java.util.concurrent.locks.Lock;
25  import java.util.concurrent.locks.ReentrantLock;
26  import org.apache.log4j.Level;
27  import org.apache.log4j.Logger;
28  import at.ac.tuwien.infosys.sm4all.copal.api.ContextException;
29  import at.ac.tuwien.infosys.sm4all.copal.api.event.ContextEvent;
30  import at.ac.tuwien.infosys.sm4all.copal.api.osgi.GenericActivator;
31  import at.ac.tuwien.infosys.sm4all.copal.api.query.ActionQuery;
32  import at.ac.tuwien.infosys.sm4all.copal.api.query.QueryDestroyedException;
33  import at.ac.tuwien.infosys.sm4all.copal.api.service.ContextQueryFactory;
34  import at.ac.tuwien.infosys.sm4all.copal.api.util.NotRegisteredException;
35  
36  /**
37   * Base {@link ContextProcessor} that correctly activates itself with COPAL and
38   * is able to process {@link ContextEvent}s.
39   * 
40   * @author sanjin
41   */
42  public abstract class BaseProcessor extends GenericActivator implements
43          ContextProcessor {
44  
45      private static final Logger LOGGER = Logger.getLogger(BaseProcessor.class);
46  
47      private final Set<ActionQuery> queries = new HashSet<ActionQuery>();
48      private final Lock lock = new ReentrantLock();
49      private final String name;
50      private final ProcessorAction[] actions;
51  
52      /**
53       * Creates an instance of {@link BaseProcessor} with specified name and
54       * {@link ProcessorAction}s as return values for {@link #getName()} and
55       * {@link #getActions()} methods respectively.
56       * 
57       * @param name the name of this {@link ContextProcessor}.
58       * @param actions the {@link ProcessorAction}s that this
59       *        {@link ContextProcessor} can process.
60       * @throws NullPointerException if specified name or {@link ProcessorAction}
61       *         s array is <code>null</code>.
62       * @throws IllegalArgumentException if specified name is an empty or blank
63       *         string or {@link ProcessorAction}s array is empty.
64       */
65      protected BaseProcessor(final String name, final ProcessorAction... actions) {
66          super(ContextQueryFactory.class.getName());
67  
68          if (null == name) {
69              throw new NullPointerException("Name cannot be null.");
70          }
71          if (name.trim().isEmpty()) {
72              throw new IllegalArgumentException(
73                      "Name cannot be an empty blank string.");
74          }
75          if (null == actions) {
76              throw new NullPointerException("Actions cannot be null.");
77          }
78          if (0 == actions.length) {
79              throw new IllegalArgumentException(
80                      "There must be at least one action.");
81          }
82  
83          this.name = name;
84          this.actions = Arrays.copyOf(actions, actions.length);
85      }
86  
87      @Override
88      public String getName() {
89          return this.name;
90      }
91  
92      @Override
93      public ProcessorAction[] getActions() {
94          return Arrays.copyOf(this.actions, this.actions.length);
95      }
96  
97      @Override
98      protected void start() {
99          if (LOGGER.isDebugEnabled()) {
100             LOGGER.debug(MessageFormat.format("Starting processor ''{0}''.",
101                     this.name));
102         }
103 
104         final ContextQueryFactory queryFactory = getDependency(ContextQueryFactory.class.getName());
105         this.lock.lock();
106         try {
107             for (final ProcessorAction action : this.actions) {
108                 final ActionQuery query = queryFactory.createActionQuery(
109                         action.getInput(), action.getName());
110                 if (!this.queries.contains(query)) {
111                     this.queries.add(query);
112                     try {
113                         query.register(this);
114                     } catch (final ContextException ex) {
115                         if (LOGGER.isEnabledFor(Level.ERROR)) {
116                             LOGGER.error(
117                                     MessageFormat.format(
118                                             "Failed to register processor ''{0}'' with action query ''{1}!",
119                                             this.name, query.getName()), ex);
120                         }
121                     }
122                 }
123             }
124         } finally {
125             this.lock.unlock();
126         }
127 
128         if (LOGGER.isInfoEnabled()) {
129             LOGGER.info(MessageFormat.format(
130                     "Successfully started processor ''{0}''!", this.name));
131         }
132     }
133 
134     @Override
135     protected void stop() {
136         if (LOGGER.isDebugEnabled()) {
137             LOGGER.debug(MessageFormat.format("Stopping processor ''{0}''.",
138                     this.name));
139         }
140 
141         this.lock.lock();
142         try {
143             for (final ActionQuery query : this.queries) {
144                 final String queryName = query.getName();
145                 try {
146                     query.unregister(this.name);
147                 } catch (final NotRegisteredException ex) {
148                     if (LOGGER.isEnabledFor(Level.WARN)) {
149                         LOGGER.warn(
150                                 MessageFormat.format(
151                                         "Processor ''{0}'' already unregistered from action query ''{1}''! Ignoring.",
152                                         this.name, queryName), ex);
153                     }
154                 }
155                 if (0 == query.getAll().length) {
156                     try {
157                         query.destroy();
158                     } catch (final QueryDestroyedException ex) {
159                         if (LOGGER.isEnabledFor(Level.WARN)) {
160                             LOGGER.warn(
161                                     MessageFormat.format(
162                                             "Action query ''{0}'' with no processors already destroyed! Ignoring.",
163                                             queryName), ex);
164                         }
165                     }
166                 }
167             }
168 
169             this.queries.clear();
170         } finally {
171             this.lock.unlock();
172         }
173 
174         if (LOGGER.isInfoEnabled()) {
175             LOGGER.info(MessageFormat.format(
176                     "Successfully stopped processor ''{0}''!", this.name));
177         }
178     }
179 }