001/*
002 *
003 * Copyright 2014 Vyacheslav Blinov
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.amp.provider;
018
019import java.io.IOException;
020
021import org.jivesoftware.smack.packet.XmlEnvironment;
022import org.jivesoftware.smack.parsing.SmackParsingException;
023import org.jivesoftware.smack.provider.ExtensionElementProvider;
024import org.jivesoftware.smack.util.StringUtils;
025import org.jivesoftware.smack.xml.XmlPullParser;
026import org.jivesoftware.smack.xml.XmlPullParserException;
027
028import org.jivesoftware.smackx.amp.AMPDeliverCondition;
029import org.jivesoftware.smackx.amp.AMPExpireAtCondition;
030import org.jivesoftware.smackx.amp.AMPMatchResourceCondition;
031import org.jivesoftware.smackx.amp.packet.AMPExtension;
032
033import org.jxmpp.JxmppContext;
034
035
036public class AMPExtensionProvider extends ExtensionElementProvider<AMPExtension> {
037
038    /**
039     * Parses a AMPExtension stanza (extension sub-packet).
040     *
041     * @param parser the XML parser, positioned at the starting element of the extension.
042     * @return a PacketExtension.
043     * @throws IOException if an I/O error occurred.
044     * @throws XmlPullParserException if an error in the XML parser occurred.
045     * @throws SmackParsingException if the Smack parser (provider) encountered invalid input.
046     */
047    @Override
048    public AMPExtension parse(XmlPullParser parser, int initialDepth, XmlEnvironment xmlEnvironment, JxmppContext jxmppContext)
049                    throws XmlPullParserException, IOException, SmackParsingException {
050        final String from = parser.getAttributeValue(null, "from");
051        final String to = parser.getAttributeValue(null, "to");
052        final String statusString = parser.getAttributeValue(null, "status");
053        AMPExtension.Status status = null;
054        if (statusString != null) {
055            try {
056                status = AMPExtension.Status.valueOf(statusString);
057            } catch (IllegalArgumentException ex) {
058                throw new SmackParsingException("Invalid AMP status: " + statusString, ex);
059            }
060        }
061
062        AMPExtension ampExtension = new AMPExtension(from, to, status);
063
064        String perHopValue = parser.getAttributeValue(null, "per-hop");
065        if (perHopValue != null) {
066            boolean perHop = Boolean.parseBoolean(perHopValue);
067            ampExtension.setPerHop(perHop);
068        }
069
070        boolean done = false;
071        while (!done) {
072            XmlPullParser.Event eventType = parser.next();
073            if (eventType == XmlPullParser.Event.START_ELEMENT) {
074                if (parser.getName().equals(AMPExtension.Rule.ELEMENT)) {
075                    String actionString = parser.getAttributeValue(null, AMPExtension.Action.ATTRIBUTE_NAME);
076                    String conditionName = parser.getAttributeValue(null, AMPExtension.Condition.ATTRIBUTE_NAME);
077                    String conditionValue = parser.getAttributeValue(null, "value");
078
079                    AMPExtension.Condition condition = createCondition(conditionName, conditionValue);
080                    AMPExtension.Action action = null;
081                    if (actionString != null) {
082                        try {
083                            action = AMPExtension.Action.valueOf(actionString);
084                        } catch (IllegalArgumentException ex) {
085                            throw new SmackParsingException("Found invalid rule action value " + actionString, ex);
086                        }
087                    }
088
089                    AMPExtension.Rule rule = new AMPExtension.Rule(action, condition);
090                    ampExtension.addRule(rule);
091                }
092            } else if (eventType == XmlPullParser.Event.END_ELEMENT) {
093                if (parser.getName().equals(AMPExtension.ELEMENT)) {
094                    done = true;
095                }
096            }
097        }
098
099        return ampExtension;
100    }
101
102    private static AMPExtension.Condition createCondition(String name, String value) throws SmackParsingException {
103        if (StringUtils.isNullOrEmpty(name)) {
104            throw new SmackParsingException("Can't have a condition without a name");
105        }
106        if (StringUtils.isNullOrEmpty(value)) {
107            throw new SmackParsingException("Can't have a condition " + name + " without value");
108        }
109
110        if (AMPDeliverCondition.NAME.equals(name)) {
111            try {
112                return new AMPDeliverCondition(AMPDeliverCondition.Value.valueOf(value));
113            } catch (IllegalArgumentException ex) {
114                throw new SmackParsingException("Found invalid rule delivery condition value " + value, ex);
115            }
116        } else if (AMPExpireAtCondition.NAME.equals(name)) {
117            return new AMPExpireAtCondition(value);
118        } else if (AMPMatchResourceCondition.NAME.equals(name)) {
119            try {
120                return new AMPMatchResourceCondition(AMPMatchResourceCondition.Value.valueOf(value));
121            } catch (IllegalArgumentException ex) {
122                throw new SmackParsingException("Found invalid rule match-resource condition value " + value, ex);
123            }
124        } else {
125            throw new SmackParsingException("Found unknown rule condition name " + name);
126        }
127    }
128}