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