summaryrefslogtreecommitdiffstats
blob: eb640514a272993e23849e3f224cf6d911bbcb67 (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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*
 * 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.session;

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.jid.JID;
import com.isode.stroke.network.Connection;
import com.isode.stroke.parser.PayloadParserFactoryCollection;
import com.isode.stroke.serializer.PayloadSerializerCollection;
import com.isode.stroke.signals.Signal1;
import com.isode.stroke.signals.Slot;
import com.isode.stroke.signals.Slot1;
import com.isode.stroke.streamstack.ConnectionLayer;
import com.isode.stroke.streamstack.StreamStack;
import com.isode.stroke.streamstack.XMPPLayer;

public abstract class Session {

    public enum SessionError {

        ConnectionReadError,
        ConnectionWriteError,
        XMLError,
        AuthenticationFailedError,
        NoSupportedAuthMechanismsError,
        UnexpectedElementError,
        ResourceBindError,
        SessionStartError,
        TLSError,
        ClientCertificateLoadError,
        ClientCertificateError
    };

    public Session(
            final Connection connection,
            final PayloadParserFactoryCollection payloadParserFactories,
            final PayloadSerializerCollection payloadSerializers,
            final EventLoop eventLoop) {
            this.connection = connection;
            this.eventLoop = eventLoop;
            this.payloadParserFactories = payloadParserFactories;
            this.payloadSerializers = payloadSerializers;
            finishing = false;
    }
    

    public void startSession() {
        initializeStreamStack();
	handleSessionStarted();
    }

    public void finishSession() {
        finishing = true;
	connection.disconnect();
	handleSessionFinished(null);
	finishing = false;
	onSessionFinished.emit(null);
    }

    public void sendElement(Element stanza) {
        xmppLayer.writeElement(stanza);
    }

    public JID getLocalJID() {
        return localJID;
    }

    public JID getRemoteJID() {
        return remoteJID;
    }
    public final Signal1<Element> onElementReceived = new Signal1<Element>();
    public final Signal1<SessionError> onSessionFinished = new Signal1<SessionError>();
    public final Signal1<ByteArray> onDataWritten = new Signal1<ByteArray>();
    public final Signal1<ByteArray> onDataRead = new Signal1<ByteArray>();

    protected void setRemoteJID(JID j) {
        remoteJID = j;
    }

    protected void setLocalJID(JID j) {
        localJID = j;
    }

    protected void finishSession(SessionError error) {
        finishing = true;
	connection.disconnect();
	handleSessionFinished(error);
	finishing = false;
	onSessionFinished.emit(error);
    }

    protected void handleSessionStarted() {
    }

    protected void handleSessionFinished(SessionError error) {
    }

    protected abstract void handleElement(Element element);

    protected abstract void handleStreamStart(ProtocolHeader header);

    protected void initializeStreamStack() {
        xmppLayer = new XMPPLayer(payloadParserFactories, payloadSerializers, StreamType.ClientStreamType);
        xmppLayer.onStreamStart.connect(new Slot1<ProtocolHeader>() {

            public void call(ProtocolHeader header) {
                handleStreamStart(header);
            }
        });
        xmppLayer.onElement.connect(new Slot1<Element>() {

            public void call(Element p1) {
                handleElement(p1);
            }
        });
        xmppLayer.onError.connect(new Slot() {

            public void call() {
                finishSession(SessionError.XMLError);
            }
        });
        xmppLayer.onDataRead.connect(onDataRead);
        xmppLayer.onWriteData.connect(onDataWritten);
        connection.onDisconnected.connect(new Slot1<Connection.Error>() {

            public void call(Connection.Error p1) {
                handleDisconnected(p1);
            }
        });
        connectionLayer = new ConnectionLayer(connection);
        streamStack = new StreamStack(xmppLayer, connectionLayer);
    }

    public XMPPLayer getXMPPLayer() {
        return xmppLayer;


    }

    public StreamStack getStreamStack() {
        return streamStack;


    }

    /*void setFinished();*/ /* This seems to be unused in Swiften*/

    private void handleDisconnected(Connection.Error connectionError) {
        if (connectionError != null) {
            switch (connectionError) {
                case ReadError:
                    finishSession(SessionError.ConnectionReadError);
                    break;
                case WriteError:
                    finishSession(SessionError.ConnectionWriteError);
                    break;
            }
        } else {
            finishSession();
        }
    }
    private JID localJID;
    private JID remoteJID;
    private Connection connection;
    private PayloadParserFactoryCollection payloadParserFactories;
    private PayloadSerializerCollection payloadSerializers;
    private XMPPLayer xmppLayer;
    private ConnectionLayer connectionLayer;
    private StreamStack streamStack;
    private boolean finishing;
    private final EventLoop eventLoop;
}