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