1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 */
18
19/**
20 * @author Vitaly A. Provodin
21 */
22
23/**
24 * Created on 29.01.2005
25 */
26package org.apache.harmony.jpda.tests.share;
27
28import java.io.DataInputStream;
29import java.io.DataOutputStream;
30import java.io.EOFException;
31import java.io.IOException;
32import java.net.Socket;
33import java.net.ServerSocket;
34
35import org.apache.harmony.jpda.tests.framework.DebuggeeSynchronizer;
36import org.apache.harmony.jpda.tests.framework.LogWriter;
37import org.apache.harmony.jpda.tests.framework.TestErrorException;
38import org.apache.harmony.jpda.tests.framework.TestOptions;
39
40/**
41 * This class implements <code>DebuggeeSynchronizer</code> interface using
42 * TCP/IP sockets. All operations can be timed out according to default timeout.
43 */
44public class JPDADebuggeeSynchronizer implements DebuggeeSynchronizer {
45
46    public final static String SGNL_READY = "ready";
47
48    public final static String SGNL_CONTINUE = "continue";
49
50    protected Socket clientSocket = null;
51
52    protected ServerSocket serverSocket = null;
53
54    protected DataOutputStream out;
55
56    protected DataInputStream in;
57
58    protected TestOptions settings;
59
60    protected LogWriter logWriter;
61
62    /**
63     * A constructor that initializes an instance of the class with specified
64     * <code>LogWriter</code> and <code>TestOptions</code>.
65     *
66     * @param logWriter
67     *            The instance of implementation of LogWriter.
68     * @param settings
69     *            Instance of test options.
70     */
71    public JPDADebuggeeSynchronizer(LogWriter logWriter, TestOptions settings) {
72        super();
73        this.logWriter = logWriter;
74        this.settings = settings;
75    }
76
77    /**
78     * Sends specified message to synchronization channel.
79     *
80     * @param message
81     *            a message to be sent.
82     */
83    public synchronized void sendMessage(String message) {
84        try {
85            out.writeUTF(message);
86            out.flush();
87            logWriter.println("[SYNC] Message sent: " + message);
88        } catch (IOException e) {
89            throw new TestErrorException(e);
90        }
91    }
92
93    /**
94     * Receives message from synchronization channel and compares it with the
95     * expected <code>message</code>.
96     *
97     * @param message
98     *            expected message.
99     * @return <code>true</code> if received string is equals to
100     *         <code>message</code> otherwise - <code>false</code>.
101     *
102     */
103    public synchronized boolean receiveMessage(String message) {
104        String msg;
105        try {
106            logWriter.println("[SYNC] Waiting for message: " + message);
107            msg = in.readUTF();
108            logWriter.println("[SYNC] Received message: " + msg);
109        } catch (EOFException e) {
110            return false;
111        } catch (IOException e) {
112            logWriter.printError(e);
113            return false;
114        }
115        return message.equalsIgnoreCase(msg);
116    }
117
118    /**
119     * Receives message from synchronization channel.
120     *
121     * @return received string or null if connection was closed.
122     */
123    public synchronized String receiveMessage() {
124        String msg;
125        try {
126            logWriter.println("[SYNC] Waiting for any messsage");
127            msg = in.readUTF();
128            logWriter.println("[SYNC] Received message: " + msg);
129        } catch (EOFException e) {
130            return null;
131        } catch (IOException e) {
132            throw new TestErrorException(e);
133        }
134        return msg;
135    }
136
137    /**
138     * Receives message from synchronization channel without Exception.
139     *
140     * @return received string
141     */
142    public synchronized String receiveMessageWithoutException(String invoker) {
143        String msg;
144        try {
145            logWriter.println("[SYNC] Waiting for any message");
146            msg = in.readUTF();
147            logWriter.println("[SYNC] Received message: " + msg);
148        } catch (Throwable thrown) {
149            if (invoker != null) {
150                logWriter.println("#### receiveMessageWithoutException: Exception occurred:");
151                logWriter.println("#### " + thrown);
152                logWriter.println("#### Invoker = " + invoker);
153            }
154            msg = "" + thrown;
155        }
156        return msg;
157    }
158
159    /**
160     * Returns socket port to be used for connection.
161     *
162     * @return port number
163     */
164    public int getSyncPortNumber() {
165        return settings.getSyncPortNumber();
166    }
167
168    /**
169     * Binds server to listen socket port.
170     *
171     * @return port number
172     */
173    public synchronized int bindServer() {
174        int port = getSyncPortNumber();
175        try {
176            logWriter.println("[SYNC] Binding socket on port: " + port);
177            serverSocket = new ServerSocket(port);
178            port = serverSocket.getLocalPort();
179            logWriter.println("[SYNC] Bound socket on port: " + port);
180            return port;
181        } catch (IOException e) {
182            throw new TestErrorException(
183                    "[SYNC] Exception in binding for socket sync connection", e);
184        }
185    }
186
187    /**
188     * Accepts sync connection form server side.
189     */
190    public synchronized void startServer() {
191        long timeout = settings.getTimeout();
192        try {
193            serverSocket.setSoTimeout((int) timeout);
194            logWriter.println("[SYNC] Accepting socket connection");
195            clientSocket = serverSocket.accept();
196            logWriter.println("[SYNC] Accepted socket connection");
197
198            clientSocket.setSoTimeout((int) timeout);
199            out = new DataOutputStream(clientSocket.getOutputStream());
200            in = new DataInputStream(clientSocket.getInputStream());
201        } catch (IOException e) {
202            throw new TestErrorException(
203                    "[SYNC] Exception in accepting socket sync connection", e);
204        }
205    }
206
207    /**
208     * Attaches for sync connection from client side..
209     */
210    public synchronized void startClient() {
211        long timeout = settings.getTimeout();
212        String host = "localhost";
213        int port = getSyncPortNumber();
214        try {
215            logWriter.println("[SYNC] Attaching socket to: " + host + ":" + port);
216            clientSocket = new Socket(host, port);
217            logWriter.println("[SYNC] Attached socket");
218
219            clientSocket.setSoTimeout((int) timeout);
220            out = new DataOutputStream(clientSocket.getOutputStream());
221            in = new DataInputStream(clientSocket.getInputStream());
222        } catch (IOException e) {
223            throw new TestErrorException(
224                    "[SYNC] Exception in attaching for socket sync connection", e);
225        }
226    }
227
228    /**
229     * Stops synchronization work. It ignores <code>IOException</code> but
230     * prints a message.
231     */
232    public void stop() {
233        try {
234            if (out != null)
235                out.close();
236            if (in != null)
237                in.close();
238            if (clientSocket != null)
239                clientSocket.close();
240            if (serverSocket != null)
241                serverSocket.close();
242        } catch (IOException e) {
243            logWriter.println
244                    ("[SYNC] Ignoring exception in closing socket sync connection: " + e);
245        }
246        logWriter.println("[SYNC] Closed socket");
247    }
248}
249