• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /barrelfish-2018-10-04/usr/eclipseclp/JavaInterface/src/com/parctechnologies/eclipse/
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) 2006 Cisco Systems, Inc.  All Rights Reserved.
18//
19// Contributor(s): Andrew Sadler, IC-Parc
20//
21// END LICENSE BLOCK
22
23package com.parctechnologies.eclipse;
24import java.io.*;
25import java.util.*;
26
27/**
28 * Wrapper class which implements the EclipseMultitaskConnection
29 * interface so as to make it seem as though the peer has control for
30 * the entire duration of ECLiPSe multitasking phases.
31 *
32 * <p> Objects of this class can only be constructed by calling the
33 * registerMultitask method of EclipseConnections. This class works by
34 * delegating most of the work to the EclipseConnection that created it.
35 *
36 *
37 * @see EclipseMultitaskConnection
38 * */
39class EclipseMultitaskConnectionImpl implements EclipseMultitaskConnection {
40  static final String STATE_EXCEPTION_MESSAGE = "Attempt to confirm/terminate multitasking phase whilst not in multitasking phase.";
41
42  protected static final Atom peerConfirmMultitaskGoal = new Atom("peer_multitask_confirm");
43  protected static final Atom peerTerminateMultitaskGoal = new Atom("peer_multitask_terminate");
44
45  static final String START_MULTITASK_MESSAGE = "start_multitask";
46  static final String END_MULTITASK_MESSAGE = "end_multitask";
47  static final String INTERACT_MULTITASK_MESSAGE = "interact";
48
49  static final int MULTITASK_RPC_TIMEOUT = 10000;
50
51  /** underlying eclipse connection */
52  EclipseConnectionImpl eclipse;
53
54  /** queue on which multitask messages are recieved */
55  FromEclipseQueue multitaskQueue;
56
57  /** Are we in a multitask phase, and if so which type. null=not in
58      multitask phase. */
59  String multitaskPhase;
60
61  /** Holds the thread on which the multitask phase messages are begin
62      delivered.  Any RPCs performed during a multitask phase fromthis
63      thread must be begin called from inside queue callbacks and so
64      they should NOT be delayed, but rather should be performed
65      immediately (so as to avoid deadlock). */
66  Thread multitaskThread;
67
68  /** Holds the delayed RPCs */
69  MultitaskGoalQueue multitaskGoalQueue;
70
71  /** Holds the MultitaskListeners */
72  List multitaskListenerList ;
73
74  EclipseMultitaskConnectionImpl(EclipseConnectionImpl eclipse,
75                                 FromEclipseQueue multitaskQueue) throws IOException {
76    this.eclipse = eclipse;
77    this.multitaskQueue = multitaskQueue;
78    this.multitaskGoalQueue = new MultitaskGoalQueue();
79    this.multitaskPhase = null;
80    this.multitaskListenerList = new LinkedList();
81    this.multitaskThread = null;
82    // register the queue listener on the multitask queue
83    multitaskQueue.setListener(new MultitaskQL());
84  }
85
86  public CompoundTerm rpc(String goal) throws EclipseException, IOException {
87    if ((multitaskPhase == null) ||
88        (Thread.currentThread() == multitaskThread)) {
89      return eclipse.rpc(goal);
90    }
91    eclipse.testTerminated();
92    return multitaskGoalQueue.execute(goal);
93  }
94
95  public CompoundTerm rpc(CompoundTerm goal) throws EclipseException, IOException {
96    if ((multitaskPhase == null) ||
97        (Thread.currentThread() == multitaskThread)) {
98      return eclipse.rpc(goal);
99    }
100    eclipse.testTerminated();
101    return multitaskGoalQueue.execute(goal);
102  }
103
104  public FromEclipseQueue getFromEclipseQueue(String name) throws EclipseException, IOException {
105    return eclipse.getFromEclipseQueue(name);
106  }
107
108  public ToEclipseQueue getToEclipseQueue(String name) throws EclipseException, IOException {
109    return eclipse.getToEclipseQueue(name);
110  }
111
112  public AsyncEclipseQueue getAsyncEclipseQueue(String name) throws EclipseException, IOException {
113    return eclipse.getAsyncEclipseQueue(name);
114  }
115
116  public void compile(File f) throws EclipseException, IOException {
117    rpc(new CompoundTermImpl("compile" , getPath(f)));
118  }
119
120  public String getPath(File f) throws EclipseException, IOException {
121    CompoundTerm call = new CompoundTermImpl("os_file_name" , null , f.getAbsolutePath() );
122    return (String) rpc(call).arg(1);
123  }
124
125  public CompoundTerm rpc(String functor, Object arg1) throws EclipseException, IOException {
126    return rpc(new CompoundTermImpl(functor,arg1));
127  }
128
129  public CompoundTerm rpc(String functor, Object arg1,
130                          Object arg2) throws EclipseException, IOException {
131    return rpc(new CompoundTermImpl(functor, arg1, arg2));
132  }
133
134  public CompoundTerm rpc(String functor, Object arg1,
135                          Object arg2, Object arg3) throws EclipseException, IOException {
136    return rpc(new CompoundTermImpl(functor, arg1, arg2, arg3));
137  }
138
139  public CompoundTerm rpc(String functor, Object arg1,
140                          Object arg2, Object arg3, Object arg4) throws EclipseException, IOException {
141    return rpc(new CompoundTermImpl(functor, arg1, arg2, arg3, arg4));
142  }
143
144  public CompoundTerm rpc(String functor, Object arg1,
145                          Object arg2, Object arg3, Object arg4,
146                          Object arg5) throws EclipseException, IOException {
147    return rpc(new CompoundTermImpl(functor, arg1, arg2, arg3, arg4, arg5));
148  }
149
150  public CompoundTerm rpc(String functor, Object[] args) throws EclipseException, IOException {
151    return rpc(new CompoundTermImpl(functor, args));
152  }
153
154  public CompoundTerm rpc(Object[] goalTerm) throws EclipseException, IOException {
155    return rpc(new CompoundTermImpl(goalTerm));
156  }
157
158  public Atom getPeerName() {
159    return eclipse.getPeerName();
160  }
161
162  /**
163   * Add the given listener to this EclipseMultitaskConnection.
164   * @return <code>this</code>.  Since this object is already
165   * registered for multitask phases. */
166  public EclipseMultitaskConnection registerMultitask(MultitaskListener multitaskListener) throws EclipseException,IOException {
167    eclipse.testTerminated();
168    if (multitaskListener != null) {
169      multitaskListenerList.add(multitaskListener);
170    }
171    return this;
172  }
173
174 /**
175   * Set the property that a multitasking phase is in progress
176   */
177  void setMultitaskPhase(String type) {
178    multitaskPhase = type ;
179  }
180
181  /**
182   * Perform any pending RPC's
183   */
184  void processMultitaskTimeSlice() {
185    // execute any delayed RPC's using the underlying EclipseConnection
186    multitaskGoalQueue.process(eclipse);
187  }
188
189
190  private static class MultitaskGoalQueue {
191    /** Stores the MultitaskGoals yet to be processed by the
192        multitask timeslice handler */
193    private List pendingGoals = new LinkedList();
194
195    /** Stores any exception which occurs as a result of errors in the
196        multitask protocol */
197    Exception multitaskProtocolException;
198
199    synchronized void setProtocolException(Exception ioe) {
200      if (multitaskProtocolException != null) {
201        multitaskProtocolException = ioe;
202      }
203    }
204
205    synchronized void testProtocolException() throws EclipseException,IOException {
206      if (multitaskProtocolException != null) {
207        if (multitaskProtocolException instanceof EclipseException) {
208          throw (EclipseException)multitaskProtocolException;
209        }
210        if (multitaskProtocolException instanceof IOException) {
211          throw (IOException)multitaskProtocolException;
212        }
213        throw new IOException("Multitask protocol error:"+
214                              multitaskProtocolException.getMessage());
215      }
216    }
217
218    /** Puts the Object (String or CompoundTerm) on the list of goals
219        to be executed and then wait until it has been. */
220    public CompoundTerm execute(Object goal) throws IOException, EclipseException {
221      MultitaskGoal mg = new MultitaskGoal(goal);
222      synchronized(this) {
223        pendingGoals.add(mg);
224      }
225      synchronized(mg) {
226        while((mg.result == null) && (mg.exception == null)) {
227          try {
228            mg.wait(MULTITASK_RPC_TIMEOUT);
229          }
230          catch(InterruptedException ie){}
231          testProtocolException();
232        }
233      }
234      // if an exception occured during the RPC, then re-throw it in
235      // the caller thread
236      if (mg.exception != null) {
237        if (mg.exception instanceof IOException) {
238          throw (IOException)(mg.exception).fillInStackTrace();
239        } else if (mg.exception instanceof EclipseException) {
240          throw (EclipseException)(mg.exception).fillInStackTrace();
241        } else {
242          throw new EclipseException(mg.exception.getMessage());
243        }
244      }
245      return mg.result;
246    }
247
248    /** Process the pending goals.  This should only be called from
249        within the handler for the multitask message queue. */
250    public void process(EclipseConnection eclipse) {
251      Iterator it;
252      synchronized(this) {
253        if (pendingGoals.isEmpty()) {
254          return;
255        }
256        // get the iterator for the current pending goals
257        it = pendingGoals.iterator();
258        // clear the pending goals before performing any RPC to avoid
259        // infinite recusion
260        pendingGoals = new LinkedList();
261      }
262      while(it.hasNext()) {
263        MultitaskGoal mg = (MultitaskGoal)(it.next());
264        try {
265          if (mg.goal instanceof CompoundTerm) {
266            mg.result = eclipse.rpc((CompoundTerm)mg.goal);
267          } else if (mg.goal instanceof String) {
268            mg.result = eclipse.rpc((String)mg.goal);
269          } else {
270            throw new EclipseException("Unknown object type ("+mg.goal+") for rpc.");
271          }
272        } catch(IOException ioe) {
273          mg.exception = ioe;
274        } catch(EclipseException ee) {
275          mg.exception = ee;
276        }
277        synchronized(mg) {
278          /* wake up the threads which were waiting for the results */
279          mg.notifyAll();
280        }
281      }
282    }
283  }
284
285  /** Class to hold the goal to be executed by the Multitask.timeslice
286   * thread */
287  private static class MultitaskGoal
288  {
289    private Object goal;
290    private CompoundTerm result;
291    private Exception exception;
292
293    private MultitaskGoal(Object goal)
294    {
295      this.goal = goal;
296    }
297  }
298
299
300
301  /** Queue listener attached to the "Multitask" stream.  Behaviour is
302      to set the state to indicate being in multi-tasking
303      mode */
304  private class MultitaskQL implements QueueListener
305  {
306    protected CompoundTerm eventTerm;
307    EXDRInputStream eis = null;
308
309
310    public void dataAvailable(Object source)
311    {
312      if(eis == null) {
313        FromEclipseQueue feq = (FromEclipseQueue) source;
314        eis = new EXDRInputStream(feq);
315      }
316      try {
317        eventTerm = (CompoundTerm) eis.readTerm();
318        processEvent();
319      } catch(EclipseException ee) {
320        // record the exception so it can be thrown by the next thread
321        // to attempt multitasking RPC
322        multitaskGoalQueue.setProtocolException(ee);
323      } catch(IOException ioe) {
324        // record the exception so it can be thrown by the next thread
325        // to attempt multitasking RPC
326        multitaskGoalQueue.setProtocolException(ioe);
327      }
328    }
329
330    void processEvent() throws EclipseException,IOException {
331      String functor = eventTerm.functor();
332      if (START_MULTITASK_MESSAGE.equals(functor)) {
333        Object typeTerm = eventTerm.arg(1);
334        if (typeTerm instanceof String) {
335          setMultitaskPhase((String)typeTerm);
336        } else if (typeTerm instanceof CompoundTerm) {
337          setMultitaskPhase(((CompoundTerm)typeTerm).functor());
338        } else {
339          throw new IOException("Multitask protocol error.  Unexpected multitasking phase type:"+typeTerm);
340        }
341        /* Record the thread on which this messages was delivered */
342        multitaskThread = Thread.currentThread();
343        /* notify all listeners */
344        for(Iterator it = multitaskListenerList.iterator(); it.hasNext(); ) {
345          MultitaskListener ml = (MultitaskListener)it.next();
346          ml.starting(EclipseMultitaskConnectionImpl.this,getMultitaskPhase());
347        }
348        /* perform any pending rpc*/
349        processMultitaskTimeSlice();
350      } else if (END_MULTITASK_MESSAGE.equals(functor)) {
351        /* notify all listeners */
352        for(Iterator it = multitaskListenerList.iterator(); it.hasNext(); ) {
353          MultitaskListener ml = (MultitaskListener)it.next();
354          ml.ending(EclipseMultitaskConnectionImpl.this,getMultitaskPhase());
355        }
356        /* perform any pending rpc*/
357        processMultitaskTimeSlice();
358        /* Clear the thread on which this messages was delivered */
359        multitaskThread = null;
360        /* leave the multitask phase */
361        setMultitaskPhase(null);
362      } else if (INTERACT_MULTITASK_MESSAGE.equals(functor)) {
363        /* perform any pending rpc*/
364        processMultitaskTimeSlice();
365      }
366    }
367
368    public void dataRequest(Object source){}
369  }
370
371  /**
372   * Gets the non-"multitasking aware" EclipseConnection from which
373   * this "multitasking aware" connection was created..
374   *
375   * <p>This method is provided incase the caller needs access to the
376   * type of the underlying connection, or if the caller requires the
377   * blocking RPC semantics of the underlying connection. */
378  public EclipseConnection getEclipseConnection() {
379    return eclipse;
380  }
381
382  protected String getMultitaskPhase() throws EclipseException, IOException {
383    eclipse.testTerminated();
384    multitaskGoalQueue.testProtocolException();
385    return multitaskPhase;
386  }
387
388  public void multitaskConfirm() throws EclipseException, IOException, IllegalStateException {
389    synchronized(this) {
390      if (multitaskPhase == null) {
391        throw new IllegalStateException(STATE_EXCEPTION_MESSAGE);
392      }
393    }
394    rpc(peerConfirmMultitaskGoal);
395  }
396
397  public void multitaskTerminate() throws EclipseException, IOException, IllegalStateException {
398    synchronized(this) {
399      if (multitaskPhase == null) {
400        throw new IllegalStateException(STATE_EXCEPTION_MESSAGE);
401      }
402    }
403    rpc(peerTerminateMultitaskGoal);
404  }
405}
406