001/**
002 *
003 * Copyright 2003-2007 Jive Software.
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 */
017
018package org.jivesoftware.smackx.xdata.provider;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.List;
023
024import org.jivesoftware.smack.provider.ExtensionElementProvider;
025import org.jivesoftware.smack.roster.packet.RosterPacket;
026import org.jivesoftware.smack.roster.provider.RosterPacketProvider;
027
028import org.jivesoftware.smackx.xdata.FormField;
029import org.jivesoftware.smackx.xdata.packet.DataForm;
030import org.jivesoftware.smackx.xdatalayout.packet.DataLayout;
031import org.jivesoftware.smackx.xdatalayout.provider.DataLayoutProvider;
032import org.jivesoftware.smackx.xdatavalidation.packet.ValidateElement;
033import org.jivesoftware.smackx.xdatavalidation.provider.DataValidationProvider;
034
035import org.xmlpull.v1.XmlPullParser;
036import org.xmlpull.v1.XmlPullParserException;
037
038/**
039 * The DataFormProvider parses DataForm packets.
040 *
041 * @author Gaston Dombiak
042 */
043public class DataFormProvider extends ExtensionElementProvider<DataForm> {
044
045    public static final DataFormProvider INSTANCE = new DataFormProvider();
046
047    @Override
048    public DataForm parse(XmlPullParser parser, int initialDepth) throws
049                    Exception {
050        DataForm.Type dataFormType = DataForm.Type.fromString(parser.getAttributeValue("", "type"));
051        DataForm dataForm = new DataForm(dataFormType);
052        outerloop: while (true) {
053            int eventType = parser.next();
054            switch (eventType) {
055            case XmlPullParser.START_TAG:
056                String name = parser.getName();
057                String namespace = parser.getNamespace();
058                switch (name) {
059                case "instructions":
060                    dataForm.addInstruction(parser.nextText());
061                    break;
062                case "title":
063                    dataForm.setTitle(parser.nextText());
064                    break;
065                case "field":
066                    dataForm.addField(parseField(parser));
067                    break;
068                case "item":
069                    dataForm.addItem(parseItem(parser));
070                    break;
071                case "reported":
072                    dataForm.setReportedData(parseReported(parser));
073                    break;
074                // See XEP-133 Example 32 for a corner case where the data form contains this extension.
075                case RosterPacket.ELEMENT:
076                    if (namespace.equals(RosterPacket.NAMESPACE)) {
077                        dataForm.addExtensionElement(RosterPacketProvider.INSTANCE.parse(parser));
078                    }
079                    break;
080                // See XEP-141 Data Forms Layout
081                case DataLayout.ELEMENT:
082                    if (namespace.equals(DataLayout.NAMESPACE)) {
083                        dataForm.addExtensionElement(DataLayoutProvider.parse(parser));
084                    }
085                    break;
086                }
087                break;
088            case XmlPullParser.END_TAG:
089                if (parser.getDepth() == initialDepth) {
090                    break outerloop;
091                }
092                break;
093            }
094        }
095        return dataForm;
096    }
097
098    private static FormField parseField(XmlPullParser parser) throws XmlPullParserException, IOException {
099        final int initialDepth = parser.getDepth();
100        final String var = parser.getAttributeValue("", "var");
101        final FormField.Type type = FormField.Type.fromString(parser.getAttributeValue("", "type"));
102
103        final FormField formField;
104        if (type == FormField.Type.fixed) {
105            formField = new FormField();
106        } else {
107            formField = new FormField(var);
108            formField.setType(type);
109        }
110        formField.setLabel(parser.getAttributeValue("", "label"));
111
112        outerloop: while (true) {
113            int eventType = parser.next();
114            switch (eventType) {
115            case XmlPullParser.START_TAG:
116                String name = parser.getName();
117                String namespace = parser.getNamespace();
118                switch (name) {
119                case "desc":
120                    formField.setDescription(parser.nextText());
121                    break;
122                case "value":
123                    formField.addValue(parser.nextText());
124                    break;
125                case "required":
126                    formField.setRequired(true);
127                    break;
128                case "option":
129                    formField.addOption(parseOption(parser));
130                    break;
131                // See XEP-122 Data Forms Validation
132                case ValidateElement.ELEMENT:
133                    if (namespace.equals(ValidateElement.NAMESPACE)) {
134                        formField.setValidateElement(DataValidationProvider.parse(parser));
135                    }
136                    break;
137                }
138                break;
139            case XmlPullParser.END_TAG:
140                if (parser.getDepth() == initialDepth) {
141                    break outerloop;
142                }
143                break;
144            }
145        }
146        return formField;
147    }
148
149    private static DataForm.Item parseItem(XmlPullParser parser) throws XmlPullParserException, IOException {
150        final int initialDepth = parser.getDepth();
151        List<FormField> fields = new ArrayList<>();
152        outerloop: while (true) {
153            int eventType = parser.next();
154            switch (eventType) {
155            case XmlPullParser.START_TAG:
156                String name = parser.getName();
157                switch (name) {
158                case "field":
159                    fields.add(parseField(parser));
160                    break;
161                }
162                break;
163            case XmlPullParser.END_TAG:
164                if (parser.getDepth() == initialDepth) {
165                    break outerloop;
166                }
167                break;
168            }
169        }
170        return new DataForm.Item(fields);
171    }
172
173    private static DataForm.ReportedData parseReported(XmlPullParser parser) throws XmlPullParserException, IOException {
174        final int initialDepth = parser.getDepth();
175        List<FormField> fields = new ArrayList<>();
176        outerloop: while (true) {
177            int eventType = parser.next();
178            switch (eventType) {
179            case XmlPullParser.START_TAG:
180                String name = parser.getName();
181                switch (name) {
182                case "field":
183                    fields.add(parseField(parser));
184                    break;
185                }
186                break;
187            case XmlPullParser.END_TAG:
188                if (parser.getDepth() == initialDepth) {
189                    break outerloop;
190                }
191                break;
192            }
193        }
194        return new DataForm.ReportedData(fields);
195    }
196
197    private static FormField.Option parseOption(XmlPullParser parser) throws XmlPullParserException, IOException {
198        final int initialDepth = parser.getDepth();
199        FormField.Option option = null;
200        String label = parser.getAttributeValue("", "label");
201        outerloop: while (true) {
202            int eventType = parser.next();
203            switch (eventType) {
204            case XmlPullParser.START_TAG:
205                String name = parser.getName();
206                switch (name) {
207                case "value":
208                    option = new FormField.Option(label, parser.nextText());
209                    break;
210                }
211                break;
212            case XmlPullParser.END_TAG:
213                if (parser.getDepth() == initialDepth) {
214                    break outerloop;
215                }
216                break;
217            }
218        }
219        return option;
220    }
221}