1 /*
2  * Copyright (C) 2016 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.googlecode.android_scripting.trigger;
18 
19 import com.google.common.collect.Maps;
20 import com.googlecode.android_scripting.facade.FacadeConfiguration;
21 import com.googlecode.android_scripting.facade.FacadeManager;
22 import com.googlecode.android_scripting.rpc.MethodDescriptor;
23 import com.googlecode.android_scripting.trigger.TriggerRepository.TriggerRepositoryObserver;
24 
25 import java.util.Map;
26 
27 import org.json.JSONArray;
28 
29 /**
30  * A {@link TriggerRepositoryObserver} that starts and stops the monitoring of events depending on
31  * whether or not triggers for the event exist.
32  *
33  * @author Felix Arends (felix.arends@gmail.com)
34  */
35 public class EventGenerationControllingObserver implements TriggerRepositoryObserver {
36   private final FacadeManager mFacadeManager;
37   private final Map<String, MethodDescriptor> mStartEventGeneratingMethodDescriptors;
38   private final Map<String, MethodDescriptor> mStopEventGeneratingMethodDescriptors;
39   private final Map<String, Integer> mEventTriggerRefCounts = Maps.newHashMap();
40 
41   /**
42    * Creates a new StartEventMonitoringObserver for the given trigger repository.
43    *
44    * @param facadeManager
45    * @param triggerRepository
46    */
EventGenerationControllingObserver(FacadeManager facadeManager)47   public EventGenerationControllingObserver(FacadeManager facadeManager) {
48     mFacadeManager = facadeManager;
49     mStartEventGeneratingMethodDescriptors =
50         FacadeConfiguration.collectStartEventMethodDescriptors();
51     mStopEventGeneratingMethodDescriptors = FacadeConfiguration.collectStopEventMethodDescriptors();
52   }
53 
incrementAndGetRefCount(String eventName)54   private synchronized int incrementAndGetRefCount(String eventName) {
55     int refCount =
56         (mEventTriggerRefCounts.containsKey(eventName)) ? mEventTriggerRefCounts.get(eventName) : 0;
57     refCount++;
58     mEventTriggerRefCounts.put(eventName, refCount);
59     return refCount;
60   }
61 
decrementAndGetRefCount(String eventName)62   private synchronized int decrementAndGetRefCount(String eventName) {
63     int refCount =
64         (mEventTriggerRefCounts.containsKey(eventName)) ? mEventTriggerRefCounts.get(eventName) : 0;
65     refCount--;
66     mEventTriggerRefCounts.put(eventName, refCount);
67     return refCount;
68   }
69 
70   @Override
onPut(Trigger trigger)71   public synchronized void onPut(Trigger trigger) {
72     // If we're not already monitoring the events corresponding to this trigger, do so.
73     if (incrementAndGetRefCount(trigger.getEventName()) == 1) {
74       startMonitoring(trigger.getEventName());
75     }
76   }
77 
78   @Override
onRemove(Trigger trigger)79   public synchronized void onRemove(Trigger trigger) {
80     // If there are no more triggers listening to this event, then we need to stop monitoring.
81     if (decrementAndGetRefCount(trigger.getEventName()) == 1) {
82       stopMonitoring(trigger.getEventName());
83     }
84   }
85 
startMonitoring(String eventName)86   private void startMonitoring(String eventName) {
87     MethodDescriptor startEventGeneratingMethod =
88         mStartEventGeneratingMethodDescriptors.get(eventName);
89     try {
90       startEventGeneratingMethod.invoke(mFacadeManager, new JSONArray());
91     } catch (Throwable t) {
92       throw new RuntimeException(t);
93     }
94   }
95 
stopMonitoring(String eventName)96   private void stopMonitoring(String eventName) {
97     MethodDescriptor stopEventGeneratingMethod =
98         mStopEventGeneratingMethodDescriptors.get(eventName);
99     try {
100       stopEventGeneratingMethod.invoke(mFacadeManager, new JSONArray());
101     } catch (Throwable t) {
102       throw new RuntimeException(t);
103     }
104   }
105 }
106