001/**
002 *
003 * Copyright the original author or authors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.pubsub;
018
019import java.text.ParseException;
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.Date;
023import java.util.List;
024import java.util.UnknownFormatConversionException;
025
026import org.jivesoftware.smack.util.XmppDateTime;
027import org.jivesoftware.smackx.xdata.Form;
028import org.jivesoftware.smackx.xdata.FormField;
029import org.jivesoftware.smackx.xdata.packet.DataForm;
030
031/**
032 * A decorator for a {@link Form} to easily enable reading and updating
033 * of subscription options.  All operations read or update the underlying {@link DataForm}.
034 * 
035 * <p>Unlike the {@link Form}.setAnswer(XXX)} methods, which throw an exception if the field does not
036 * exist, all <b>SubscribeForm.setXXX</b> methods will create the field in the wrapped form
037 * if it does not already exist.
038 * 
039 * @author Robin Collier
040 */
041public class SubscribeForm extends Form
042{       
043        public SubscribeForm(DataForm configDataForm)
044        {
045                super(configDataForm);
046        }
047        
048        public SubscribeForm(Form subscribeOptionsForm)
049        {
050                super(subscribeOptionsForm.getDataFormToSend());
051        }
052        
053        public SubscribeForm(FormType formType)
054        {
055                super(formType.toString());
056        }
057        
058        /**
059         * Determines if an entity wants to receive notifications.
060         * 
061         * @return true if want to receive, false otherwise
062         */
063        public boolean isDeliverOn()
064        {
065                return parseBoolean(getFieldValue(SubscribeOptionFields.deliver));
066        }
067        
068        /**
069         * Sets whether an entity wants to receive notifications.
070         *
071         * @param deliverNotifications
072         */
073        public void setDeliverOn(boolean deliverNotifications)
074        {
075                addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
076                setAnswer(SubscribeOptionFields.deliver.getFieldName(), deliverNotifications);
077        }
078
079        /**
080         * Determines if notifications should be delivered as aggregations or not.
081         * 
082         * @return true to aggregate, false otherwise
083         */
084        public boolean isDigestOn()
085        {
086                return parseBoolean(getFieldValue(SubscribeOptionFields.digest));
087        }
088        
089        /**
090         * Sets whether notifications should be delivered as aggregations or not.
091         * 
092         * @param digestOn true to aggregate, false otherwise 
093         */
094        public void setDigestOn(boolean digestOn)
095        {
096                addField(SubscribeOptionFields.deliver, FormField.TYPE_BOOLEAN);
097                setAnswer(SubscribeOptionFields.deliver.getFieldName(), digestOn);
098        }
099
100        /**
101         * Gets the minimum number of milliseconds between sending notification digests
102         * 
103         * @return The frequency in milliseconds
104         */
105        public int getDigestFrequency()
106        {
107                return Integer.parseInt(getFieldValue(SubscribeOptionFields.digest_frequency));
108        }
109
110        /**
111         * Sets the minimum number of milliseconds between sending notification digests
112         * 
113         * @param frequency The frequency in milliseconds
114         */
115        public void setDigestFrequency(int frequency)
116        {
117                addField(SubscribeOptionFields.digest_frequency, FormField.TYPE_TEXT_SINGLE);
118                setAnswer(SubscribeOptionFields.digest_frequency.getFieldName(), frequency);
119        }
120
121        /**
122         * Get the time at which the leased subscription will expire, or has expired.
123         * 
124         * @return The expiry date
125         */
126        public Date getExpiry()
127        {
128                String dateTime = getFieldValue(SubscribeOptionFields.expire);
129                try
130                {
131                        return XmppDateTime.parseDate(dateTime);
132                }
133                catch (ParseException e)
134                {
135                        UnknownFormatConversionException exc = new UnknownFormatConversionException(dateTime);
136                        exc.initCause(e);
137                        throw exc;
138                }
139        }
140        
141        /**
142         * Sets the time at which the leased subscription will expire, or has expired.
143         * 
144         * @param expire The expiry date
145         */
146        public void setExpiry(Date expire)
147        {
148                addField(SubscribeOptionFields.expire, FormField.TYPE_TEXT_SINGLE);
149                setAnswer(SubscribeOptionFields.expire.getFieldName(), XmppDateTime.formatXEP0082Date(expire));
150        }
151        
152        /**
153         * Determines whether the entity wants to receive an XMPP message body in 
154         * addition to the payload format.
155         * 
156         * @return true to receive the message body, false otherwise
157         */
158        public boolean isIncludeBody()
159        {
160                return parseBoolean(getFieldValue(SubscribeOptionFields.include_body));
161        }
162        
163        /**
164         * Sets whether the entity wants to receive an XMPP message body in 
165         * addition to the payload format.
166         * 
167         * @param include true to receive the message body, false otherwise
168         */
169        public void setIncludeBody(boolean include)
170        {
171                addField(SubscribeOptionFields.include_body, FormField.TYPE_BOOLEAN);
172                setAnswer(SubscribeOptionFields.include_body.getFieldName(), include);
173        }
174
175        /**
176         * Gets the {@link PresenceState} for which an entity wants to receive 
177         * notifications.
178         * 
179         * @return the list of states
180         */
181        public List<PresenceState> getShowValues()
182        {
183                ArrayList<PresenceState> result = new ArrayList<PresenceState>(5);
184                
185                for (String state : getFieldValues(SubscribeOptionFields.show_values))
186                {
187                        result.add(PresenceState.valueOf(state));
188                }
189                return result;
190        }
191        
192        /**
193         * Sets the list of {@link PresenceState} for which an entity wants
194         * to receive notifications.
195         * 
196         * @param stateValues The list of states
197         */
198        public void setShowValues(Collection<PresenceState> stateValues)
199        {
200                ArrayList<String> values = new ArrayList<String>(stateValues.size());
201                
202                for (PresenceState state : stateValues)
203                {
204                        values.add(state.toString());
205                }
206                addField(SubscribeOptionFields.show_values, FormField.TYPE_LIST_MULTI);
207                setAnswer(SubscribeOptionFields.show_values.getFieldName(), values);
208        }
209        
210        
211        static private boolean parseBoolean(String fieldValue)
212        {
213                return ("1".equals(fieldValue) || "true".equals(fieldValue));
214        }
215
216        private String getFieldValue(SubscribeOptionFields field)
217        {
218                FormField formField = getField(field.getFieldName());
219                
220                return formField.getValues().get(0);
221        }
222
223        private List<String> getFieldValues(SubscribeOptionFields field)
224        {
225                FormField formField = getField(field.getFieldName());
226                
227                return formField.getValues();
228        }
229
230        private void addField(SubscribeOptionFields nodeField, String type)
231        {
232                String fieldName = nodeField.getFieldName();
233                
234                if (getField(fieldName) == null)
235                {
236                        FormField field = new FormField(fieldName);
237                        field.setType(type);
238                        addField(field);
239                }
240        }
241}