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.jxmpp.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(DataForm.Type formType)
054    {
055        super(formType);
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.bool);
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.bool);
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.bool);
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, FormField.Type 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}