1// BEGIN LICENSE BLOCK
2// Version: CMPL 1.1
3//
4// The contents of this file are subject to the Cisco-style Mozilla Public
5// License Version 1.1 (the "License"); you may not use this file except
6// in compliance with the License.  You may obtain a copy of the License
7// at www.eclipse-clp.org/license.
8//
9// Software distributed under the License is distributed on an "AS IS"
10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11// the License for the specific language governing rights and limitations
12// under the License.
13//
14// The Original Code is  The ECLiPSe Constraint Logic Programming System.
15// The Initial Developer of the Original Code is  Cisco Systems, Inc.
16// Portions created by the Initial Developer are
17// Copyright (C) 2000 - 2006 Cisco Systems, Inc.  All Rights Reserved.
18//
19// Contributor(s): Stefano Novello / Josh Singer, Parc Technologies
20//
21// END LICENSE BLOCK
22
23//Title:        Java/ECLiPSe interface
24//Version:      $Id: FromEclipseQueue.java,v 1.1 2006/09/23 01:54:10 snovello Exp $
25//Author:       Stefano Novello / Josh Singer
26//Company:      Parc Technologies
27//Description:  Queue for sending ECLiPSe data to Java.
28package com.parctechnologies.eclipse;
29import java.io.*;
30import java.util.*;
31
32/**
33 * A queue for
34 * sending data from ECLiPSe to Java. This class performs no processing of the
35 * data and cannot for example, deal with EXDR format (see {@link EXDRInputStream}
36 * for a class which can handle this). <p>
37 *
38 * In addition to the standard methods inherited from its superclass, this class
39 * also provides the ability to attach a {@link QueueListener} object to the
40 * FromEclipseQueue, as a handler for incoming data.
41 * <p>
42 * There is no public constructor; to access an <i>FromEclipseQueue</i> use the
43 * <code>createFromEclipseQueue()</code> of an object implementing the {@link
44 * EclipseConnection} interface or the <code>getEclipseStderr()</code> or
45 * <code>getEclipseStdout()</code> method of an object implementing the
46 * {@link EclipseEngine} interface.
47 *
48 */
49public class FromEclipseQueue extends InputStream {
50    /**
51     * This is the eclipse numeric id for the queue
52     * it is used to uniquely identify the stream
53     */
54    private int id;
55    /**
56     * Handler for new data on queue
57     */
58    private QueueListener listener = null;
59    /**
60     * Name of the queue
61     */
62    private String name;
63
64    /**
65     * The eclipse which this is a queue from
66     */
67    private EclipseConnectionImpl eclipse;
68
69    /**
70     * Flag to indicate whether or not the queue has been closed.
71     */
72    private boolean isClosed = false;
73
74    /**
75     * Flag indicating whether this is a system or user queue. The eclipse side of
76     * a System queue does not get closed when the EclipseConnectionImpl's
77     * closeAllQueues method is called. Examples of system queues are ec_rpc_in
78     * ec_rpc_out, and standard stream queues.
79     */
80    private boolean systemQueue = false;
81
82
83    /**
84     * make new queue
85     */
86    FromEclipseQueue(int id,String name, EclipseConnectionImpl eclipse)
87    {
88        this.eclipse = eclipse;
89        this.id = id;
90        this.name = name;
91    }
92
93    int getID()
94    {
95      return id;
96    }
97
98    /**
99     * Returns true if this queue is a system queue, such as ec_rpc_in.
100     */
101    boolean isSystemQueue()
102    {
103      return(systemQueue);
104    }
105
106    /**
107     * sets flag indicating wether this is a system queue
108     */
109    void setSystemQueue(boolean newValue)
110    {
111      systemQueue = newValue;
112    }
113
114
115
116    // overrides superclass method. Return the number of bytes which
117    // can be read from the FromEclipseQueue stream without blocking.
118    public int available() throws IOException
119    {
120      testClosed();
121      return(eclipse.availableOnStream(id));
122    }
123
124    /**
125     * Read bytes from the FromEclipseQueue into a byte array.
126     * <code>len</code> bytes are read from the queue and stored in byte
127     * array <code>b</code> at offset <code>off</code>.
128     *
129     * @return the number of bytes read.
130     *
131     */
132    public int read(byte[] b, int off, int len) throws IOException
133    {
134      testClosed();
135      // read len bytes from the Eclipse stream and copy them into b at
136      // offset off. Set read to the number of bytes read.
137      int read = eclipse.readFromStream(id,off,len,b);
138      // If nothing was read
139/*      if(read == 0)
140      {
141        try
142        {
143          // pass control to eclipse to allow events to be
144          // handled somehow here.
145
146          // try the read operation again
147          read = eclipse.readFromStream(id,off,len,b);
148        }
149        catch(EclipseException e)
150        {
151          throw(new IOException("Problem handling events on ECLiPSe side."));
152        }
153      }
154*/
155      // Return the number of bytes read
156      return read;
157
158    }
159
160    public int read() throws IOException
161    {
162      testClosed();
163      return(eclipse.readByteFromStream(id));
164    }
165
166    /**
167     * Called to notify a listener, if there is one, that data is available
168     */
169    void notifyAvailable()
170    {
171        if (listener != null)
172        {
173            listener.dataAvailable(this);
174        }
175    }
176
177    /**
178     * Attach a <i>QueueListener</i> to this <i>FromEclipseQueue</i> for handling
179     * incoming data. When ECLiPSe
180     * flushes the
181     * queue, the <code>dataAvailable()</code> method of the
182     * <i>QueueListener</i> is invoked.
183     */
184    public void setListener(QueueListener l) throws IOException
185    {
186      testClosed();
187      listener = l;
188    }
189
190    /**
191     * Detach any <i>QueueListener</i> from this <i>FromEclipseQueue</i>.
192     */
193    public void removeListener() throws IOException
194    {
195      testClosed();
196      listener = null;
197    }
198
199    /**
200     * Closes the queue (both eclipse and Java sides), removing any listener.
201     */
202    public void close() throws IOException
203    {
204      testClosed();
205      close_cleanup();
206      eclipse.closeFromEclipseStreamEclipseSide(id);
207      eclipse.closeFromEclipseStreamJavaSide(id);
208    }
209
210    // method to clean up locally
211    void close_cleanup()
212    {
213      try
214      {
215        this.removeListener();
216      }
217      catch(IOException ioe)
218      {
219        // only thrown if the queue has already been closed, which it hasn't
220        System.err.println("Error: removal of listener threw an IOException.");
221        System.err.flush();
222      }
223      isClosed = true;
224    }
225
226    /**
227     * Test whether the queue has been closed; if so, throw an IOException
228     * "Operation not possible: stream closed."
229     */
230    private void testClosed() throws IOException
231    {
232      if(isClosed)
233      {
234        throw new IOException("Operation not possible: stream closed.");
235      }
236    }
237
238}
239