summaryrefslogtreecommitdiffstats
blob: 34c25b534612ba022887312fb6dc6d178e9871b3 (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
/*
 * Copyright (c) 2010 Remko Tronçon
 * Licensed under the GNU General Public License v3.
 * See Documentation/Licenses/GPLv3.txt for more information.
 */
/*
 * Copyright (c) 2010-2011, Isode Limited, London, England.
 * All rights reserved.
 */
package com.isode.stroke.streamstack;

import com.isode.stroke.base.ByteArray;
import com.isode.stroke.elements.Element;
import com.isode.stroke.elements.ProtocolHeader;
import com.isode.stroke.elements.StreamType;
import com.isode.stroke.eventloop.EventLoop;
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<ByteArray> onWriteData = new Signal1<ByteArray>();
    public final Signal1<ByteArray> onDataRead = new Signal1<ByteArray>();
    public final Signal onError = new Signal();

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

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

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

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

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

    public void writeData(String data) {
        writeDataInternal(new ByteArray(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(ByteArray data) {
        handleDataReadInternal(data);
    }

    protected void writeDataInternal(ByteArray 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(ByteArray data) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

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

    private void handleDataReadInternal(ByteArray 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(ByteArray data) {
        fakeStreamLayer_.writeDataToChildLayer(data);
    }
}