View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.push.cdi;
21  
22  import java.io.Serializable;
23  import java.util.Collection;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  import java.util.concurrent.Future;
30  import javax.enterprise.inject.spi.BeanManager;
31  import javax.enterprise.inject.spi.CDI;
32  import javax.faces.FacesException;
33  import javax.faces.context.FacesContext;
34  import javax.faces.push.PushContext;
35  import org.apache.myfaces.cdi.util.CDIUtils;
36  
37  /**
38   *
39   */
40  public class PushContextImpl implements PushContext
41  {
42      
43      private final String channel;
44  
45      public PushContextImpl(String channel)
46      {
47          this.channel = channel;
48      }
49  
50      /**
51       * @return the channel
52       */
53      public String getChannel()
54      {
55          return channel;
56      }
57  
58      @Override
59      public Set<Future<Void>> send(Object message)
60      {
61          //1. locate the channel and define the context
62          String channel = getChannel();
63          BeanManager beanManager = null;
64          FacesContext facesContext = FacesContext.getCurrentInstance();
65          if (facesContext != null)
66          {
67              beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
68          }
69          else
70          {
71              beanManager = CDI.current().getBeanManager();
72          }
73          
74          WebsocketApplicationBean appTokenBean = CDIUtils.getInstance(beanManager, 
75                  WebsocketApplicationBean.class, false);
76          WebsocketViewBean viewTokenBean = null;
77          WebsocketSessionBean sessionTokenBean = null;
78          
79          if (CDIUtils.isSessionScopeActive(beanManager))
80          {
81              sessionTokenBean = CDIUtils.getInstance(beanManager, WebsocketSessionBean.class, false);
82              if (CDIUtils.isViewScopeActive(beanManager))
83              {
84                  viewTokenBean = CDIUtils.getInstance(beanManager, WebsocketViewBean.class, false);
85              }
86          }
87          
88          if (appTokenBean == null)
89          {
90              // No base bean to push message
91              return Collections.emptySet();
92          }
93          
94          List<String> channelTokens;
95          
96          if (viewTokenBean != null && viewTokenBean.isChannelAvailable(channel))
97          {
98              // Use view scope for context
99              channelTokens = viewTokenBean.getChannelTokensFor(channel);
100         }
101         else if (sessionTokenBean != null && sessionTokenBean.isChannelAvailable(getChannel()))
102         {
103             // Use session scope for context
104             channelTokens = sessionTokenBean.getChannelTokensFor(channel);
105         }
106         else if (appTokenBean != null && appTokenBean.isChannelAvailable(getChannel()))
107         {
108             // Use application scope for context
109             channelTokens = appTokenBean.getChannelTokensFor(channel);
110         }
111         else
112         {
113             throw new FacesException("CDI bean not found for push message");
114         }
115         
116         //2. send the message
117         
118         if (channelTokens != null && !channelTokens.isEmpty())
119         {
120             Set<Future<Void>> result = null;
121             for (String channelToken : channelTokens)
122             {
123                 if (result == null)
124                 {
125                     result = WebsocketApplicationSessionHolder.send(channelToken, message);
126                 }
127                 else
128                 {
129                     result.addAll(WebsocketApplicationSessionHolder.send(channelToken, message));
130                 }
131             }
132             return result;
133         }
134         
135         return Collections.emptySet();
136     }
137 
138     @Override
139     public <S extends Serializable> Set<Future<Void>> send(Object message, S user)
140     {
141         return send(message, Collections.singleton(user)).get(user);
142     }
143 
144     @Override
145     public <S extends Serializable> Map<S, Set<Future<Void>>> send(Object message, Collection<S> users)
146     {
147         //1. locate the channel and define the context
148         String channel = getChannel();
149         BeanManager beanManager = null;
150         FacesContext facesContext = FacesContext.getCurrentInstance();
151         if (facesContext != null)
152         {
153             beanManager = CDIUtils.getBeanManager(facesContext.getExternalContext());
154         }
155         else
156         {
157             beanManager = CDI.current().getBeanManager();
158         }
159         
160         WebsocketApplicationBean appTokenBean = CDIUtils.getInstance(beanManager, 
161                 WebsocketApplicationBean.class, false);
162         WebsocketViewBean viewTokenBean = null;
163         WebsocketSessionBean sessionTokenBean = null;
164         
165         if (CDIUtils.isSessionScopeActive(beanManager))
166         {
167             sessionTokenBean = CDIUtils.getInstance(beanManager, WebsocketSessionBean.class, false);
168             if (CDIUtils.isViewScopeActive(beanManager))
169             {
170                 viewTokenBean = CDIUtils.getInstance(beanManager, WebsocketViewBean.class, false);
171             }
172         }
173         
174         if (appTokenBean == null)
175         {
176             // No base bean to push message
177             return Collections.emptyMap();
178         }
179 
180         Map<S, Set<Future<Void>>> result = new HashMap<S, Set<Future<Void>>>();
181         
182         if (viewTokenBean != null && viewTokenBean.isChannelAvailable(channel))
183         {
184             // Use view scope for context
185             for (S user : users)
186             {
187                 result.put(user, send(viewTokenBean.getChannelTokensFor(channel, user), message));
188             }
189         }
190         else if (sessionTokenBean != null && sessionTokenBean.isChannelAvailable(getChannel()))
191         {
192             // Use session scope for context
193             for (S user : users)
194             {
195                 result.put(user, send(sessionTokenBean.getChannelTokensFor(channel, user), message));
196             }
197         }
198         else if (appTokenBean != null && appTokenBean.isChannelAvailable(getChannel()))
199         {
200             // Use application scope for context
201             for (S user : users)
202             {
203                 result.put(user, send(appTokenBean.getChannelTokensFor(channel, user), message));
204             }
205         }
206         else
207         {
208             throw new FacesException("CDI bean not found for push message");
209         }
210         
211         //2. send the message
212         return result;
213     }
214     
215     private Set<Future<Void>> send(
216             List<String> channelTokens, Object message)
217     {
218         if (channelTokens != null && !channelTokens.isEmpty())
219         {
220             Set<Future<Void>> result = null;
221             for (int i = 0; i < channelTokens.size(); i++)
222             {
223                 String channelToken = channelTokens.get(i);
224                 if (result == null)
225                 {
226                     result = WebsocketApplicationSessionHolder.send(channelToken, message);
227                 }
228                 else
229                 {
230                     result.addAll(WebsocketApplicationSessionHolder.send(channelToken, message));
231                 }
232             }
233             return result;
234         }
235         return Collections.emptySet();
236     }
237 }