summaryrefslogtreecommitdiffstats
blob: 6d14b9b43c9e846c3ed98777fbb7517c28099965 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 * Copyright (c) 2010-2015, Isode Limited, London, England.
 * All rights reserved.
 */
package com.isode.stroke.streamstack;

import com.isode.stroke.base.SafeByteArray;
import com.isode.stroke.elements.Element;
import com.isode.stroke.elements.ProtocolHeader;
import com.isode.stroke.elements.StreamType;
import com.isode.stroke.parser.PayloadParserFactoryCollection;
import com.isode.stroke.parser.XMPPParser;
import com.isode.stroke.parser.XMPPParserClient;
import com.isode.stroke.serializer.PayloadSerializerCollection;
import com.isode.stroke.serializer.XMPPSerializer;
import com.isode.stroke.signals.Signal;
import com.isode.stroke.signals.Signal1;

/**
 * This uses the inner StreamLayer to work around the HighLayer not having
 * implementations because of the lack of multiple inheritance.
 * Swiften doesn't require an eventLoop, Stroke does because of
 * XML parsing being multi-threaded here.
 */
public class XMPPLayer implements HighLayer, XMPPParserClient {
    public final Signal1<ProtocolHeader> onStreamStart = new Signal1<ProtocolHeader>();
    public final Signal1<Element> onElement = new Signal1<Element>();
    public final Signal1<SafeByteArray> onWriteData = new Signal1<SafeByteArray>();
    public final Signal1<SafeByteArray> onDataRead = new Signal1<SafeByteArray>();
    public final Signal onError = new Signal();

    private PayloadParserFactoryCollection payloadParserFactories_;
    private XMPPParser xmppParser_;
    private PayloadSerializerCollection payloadSerializers_;
    private XMPPSerializer xmppSerializer_;
    private boolean resetParserAfterParse_;
    private boolean inParser_;
    private boolean setExplictNSonTopLevelElements_;

    public XMPPLayer(
            PayloadParserFactoryCollection payloadParserFactories,
            PayloadSerializerCollection payloadSerializers,
            StreamType streamType) {
        this(payloadParserFactories, payloadSerializers, streamType, false);
    }

    public XMPPLayer(
            PayloadParserFactoryCollection payloadParserFactories,
            PayloadSerializerCollection payloadSerializers,
            StreamType streamType,
            boolean setExplictNSonTopLevelElements) {
        payloadParserFactories_ = payloadParserFactories;
        payloadSerializers_ = payloadSerializers;
        setExplictNSonTopLevelElements_ = setExplictNSonTopLevelElements;
        resetParserAfterParse_ = false;
        inParser_ = false;
        xmppParser_ = new XMPPParser(this, payloadParserFactories_);
        xmppSerializer_ = new XMPPSerializer(payloadSerializers_, streamType, setExplictNSonTopLevelElements);
    }

    public void writeHeader(ProtocolHeader header) {
        writeDataInternal(new SafeByteArray(xmppSerializer_.serializeHeader(header)));
    }

    public void writeFooter() {
        writeDataInternal(new SafeByteArray(xmppSerializer_.serializeFooter()));
    }

    public void writeElement(Element element) {
        writeDataInternal(new SafeByteArray(xmppSerializer_.serializeElement(element)));
    }

    public void writeData(String data) {
        writeDataInternal(new SafeByteArray(data));
    }

    public void resetParser() {
        if (inParser_) {
            resetParserAfterParse_ = true;
        }
        else {
            doResetParser();
        }
    }

    /**
     * Should be protected, but can't because of interface implementation.
     * @param data
     */
    public void handleDataRead(SafeByteArray data) {
        handleDataReadInternal(data);
    }

    protected void writeDataInternal(SafeByteArray data) {
        onWriteData.emit(data);
        writeDataToChildLayer(data);
    }

    public void handleStreamStart(ProtocolHeader header) {
        onStreamStart.emit(header);
    }

    public void handleElement(Element element) {
        onElement.emit(element);
    }

    public void handleStreamEnd() {
    }

    private void doResetParser() {
        xmppParser_ = new XMPPParser(this, payloadParserFactories_);
        resetParserAfterParse_ = false;
    }
    
    /* Multiple-inheritance workarounds */

    private StreamLayer fakeStreamLayer_ = new StreamLayer() {
        public void writeData(SafeByteArray data) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void handleDataRead(SafeByteArray data) {
            handleDataReadInternal(data);
        }
    };

    private void handleDataReadInternal(SafeByteArray data) {
        onDataRead.emit(data);
        inParser_ = true;
        if(!xmppParser_.parse(data.toString())) {
            inParser_ = false;
            onError.emit();
            return;
        }
        inParser_ = false;
        if (resetParserAfterParse_) {
            doResetParser();
        }
    }

    public LowLayer getChildLayer() {
        return fakeStreamLayer_.getChildLayer();
    }

    public void setChildLayer(LowLayer childLayer) {
        fakeStreamLayer_.setChildLayer(childLayer);
    }

    public void writeDataToChildLayer(SafeByteArray data) {
        fakeStreamLayer_.writeDataToChildLayer(data);
    }
}