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: ToEclipseQueue.java,v 1.1 2006/09/23 01:54:12 snovello Exp $
25//Author:       Stefano Novello / Josh Singer
26//Company:      Parc Technologies
27//Description:  Queue to send Java data to Eclipse
28package com.parctechnologies.eclipse;
29import java.util.*;
30import java.io.*;
31
32/**
33 * A queue for
34 * sending data from Java to ECLiPSe. This class performs no processing of the
35 * data and cannot for example, convert to EXDR format (see {@link EXDROutputStream}
36 * for a class which can do 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 * ToEclipseQueue, as a handler for data requests from ECLiPSe.
41 * <p>
42 * There is no public constructor; to access an <i>ToEclipseQueue</i> use the
43 * <code>createToEclipseQueue()</code> of an object implementing the {@link
44 * EclipseConnection} interface or the <code>getEclipseStdin()</code> method of
45 * an object implementing the {@link EclipseEngine} interface.
46 *
47 */
48public class ToEclipseQueue extends OutputStream {
49
50    /* Name of queue which is to be used by the user on the Java side.
51       The corresponding stream on the Eclipse
52       side may be referenced by the same string, but may also have other names. */
53    private String name;
54    /* Stream number uniquely identifying the stream on the Eclipse side, and also
55       used by classes inside this package on the Java side */
56    private int id;
57    /* The Eclipse which this queue is a queue to. Declared as an
58       EclipseConnectionImpl because this is the abstract class containing the methods
59       such as writeToStream which are called from this class */
60    private EclipseConnectionImpl eclipse;
61
62    /**
63     * Listener for handling outgoing data, none by default
64     */
65    private QueueListener listener = null;
66
67    /**
68     * Flag to indicate whether close() method has been called.
69     */
70    private boolean isClosed = false;
71
72    /**
73     * Flag indicating whether this is a system or user queue. The eclipse side of
74     * a System queue does not get closed when the EclipseConnectionImpl's
75     * closeAllQueues method is called. Examples of system queues are ec_rpc_in
76     * ec_rpc_out, and standard stream queues.
77     */
78    private boolean systemQueue = false;
79
80
81    /**
82     * construct a toEclipseQueue
83     */
84    ToEclipseQueue(int id,String name, EclipseConnectionImpl eclipse)
85    {
86        this.eclipse = eclipse;
87        this.id = id;
88        this.name = name;
89    }
90
91    int getID()
92    {
93      return(id);
94    }
95
96    /**
97     * Returns true if this queue is a system queue, such as ec_rpc_in.
98     */
99    boolean isSystemQueue()
100    {
101      return(systemQueue);
102    }
103
104    /**
105     * sets flag indicating wether this is a system queue
106     */
107    void setSystemQueue(boolean newValue)
108    {
109      systemQueue = newValue;
110    }
111
112
113    // write a single byte: calls writeByteToStream in the
114    // EclipseConnectionImpl class.
115
116    public void write(int b) throws IOException
117    {
118      testClosed();
119      eclipse.writeByteToStream(id, (byte) b);
120    }
121
122    // invokes a method in the underlying eclipse which writes to a stream
123
124    public void write(byte b[], int off, int len) throws IOException
125    {
126      testClosed();
127      eclipse.writeToStream(id,b,off,len);
128    }
129
130  /**
131     * Attach a <i>QueueListener</i> to this <i>ToEclipseQueue</i> for handling
132     * requests for data. When ECLiPSe
133     * tries to read from an empty queue with a <i>QueueListener</i>
134     * attached,
135     * the <code>dataAvailable()</code> method of the
136     * <i>QueueListener</i> is invoked.
137     */
138    public void setListener(QueueListener l) throws IOException
139    {
140      testClosed();
141      listener = l;
142    }
143
144    /**
145     * Detach any <i>QueueListener</i> from this <i>ToEclipseQueue</i>.
146     */
147    public void removeListener() throws IOException
148    {
149      testClosed();
150      listener = null;
151    }
152
153    /**
154     * Called to notify that data has been requested, this forwards the request
155     * to any listeners.
156     */
157    void notifyRequest()
158    {
159      // if there is a listener, invoke its dataRequest method
160      if(listener != null)
161      {
162        listener.dataRequest(this);
163      }
164    }
165
166    /**
167     * Calls the superclass' <code>flush</code> method
168     */
169    public void flush() throws IOException
170    {
171      testClosed();
172      // Get the underlying eclipse to flush the relevant stream
173      eclipse.flushStream(this.id);
174
175      // somehow here allow eclipse to handle events
176    }
177
178    /**
179     * Closes the queue (both eclipse and Java sides), removing any listener.
180     */
181    public void close() throws IOException
182    {
183      testClosed();
184      close_cleanup();
185      eclipse.closeToEclipseStreamEclipseSide(id);
186      eclipse.closeToEclipseStreamJavaSide(id);
187    }
188
189    // method to clean up locally
190    void close_cleanup()
191    {
192      try
193      {
194        this.removeListener();
195      }
196      catch(IOException ioe)
197      {
198        // only thrown if the queue has already been closed, which it hasn't
199        System.err.println("Error: removal of listener threw an IOException.");
200        System.err.flush();
201      }
202      isClosed = true;
203    }
204    /**
205     * Test whether the queue has been closed; if so, throw an IOException
206     * "Operation not possible: stream closed."
207     */
208    private void testClosed() throws IOException
209    {
210      if(isClosed)
211      {
212        throw new IOException("Operation not possible: stream closed.");
213      }
214    }
215
216}
217