001/* A director to control the execution of ExecutionChoice actors. 
002 * 
003 * Copyright (c) 2012 The Regents of the University of California.
004 * All rights reserved.
005 *
006 * '$Author: crawl $'
007 * '$Date: 2014-02-19 18:21:33 +0000 (Wed, 19 Feb 2014) $' 
008 * '$Revision: 32608 $'
009 * 
010 * Permission is hereby granted, without written agreement and without
011 * license or royalty fees, to use, copy, modify, and distribute this
012 * software and its documentation for any purpose, provided that the above
013 * copyright notice and the following two paragraphs appear in all copies
014 * of this software.
015 *
016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
020 * SUCH DAMAGE.
021 *
022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
027 * ENHANCEMENTS, OR MODIFICATIONS.
028 *
029 */
030package org.kepler.ddp.actor;
031
032import java.util.Iterator;
033import java.util.LinkedList;
034import java.util.List;
035
036import ptolemy.actor.Director;
037import ptolemy.actor.FiringEvent;
038import ptolemy.actor.IOPort;
039import ptolemy.actor.IOPortEvent;
040import ptolemy.actor.Receiver;
041import ptolemy.actor.lib.hoc.Case;
042import ptolemy.actor.lib.hoc.CaseDirector;
043import ptolemy.actor.lib.hoc.Refinement;
044import ptolemy.actor.parameters.ParameterPort;
045import ptolemy.actor.parameters.PortParameter;
046import ptolemy.data.BooleanToken;
047import ptolemy.data.StringToken;
048import ptolemy.data.Token;
049import ptolemy.data.expr.Parameter;
050import ptolemy.data.expr.StringParameter;
051import ptolemy.domains.ddf.kernel.DDFDirector;
052import ptolemy.kernel.CompositeEntity;
053import ptolemy.kernel.util.IllegalActionException;
054import ptolemy.kernel.util.NameDuplicationException;
055import ptolemy.kernel.util.NamedObj;
056import ptolemy.kernel.util.Workspace;
057
058/**
059 * A director to control the execution of execution choice actors.
060 * 
061 * @author Daniel Crawl
062 * @version $Id: ExecutionChoiceDirector.java 32608 2014-02-19 18:21:33Z crawl $
063 */
064public class ExecutionChoiceDirector extends CaseDirector {
065
066    /** Create a new ExecutionChoiceDirector in a container
067     *  with a specific name.
068     */
069    public ExecutionChoiceDirector(CompositeEntity container, String name)
070            throws IllegalActionException, NameDuplicationException {
071        super(container, name);
072        
073        // make sure the container in ExecutionChoice
074        // XXX do not do this check since container may be CompositeClassEntity
075        /*
076        NamedObj namedObj = getContainer();
077        if (!(namedObj instanceof ExecutionChoice)) {
078            throw new IllegalActionException(
079                    "ExecutionChoiceDirector may only be used with the ExecutionChoice actor.");
080        }
081        */
082    }
083
084    /** Clone this director into the specified workspace. */
085    @Override
086    public Object clone(Workspace workspace) throws CloneNotSupportedException {
087        ExecutionChoiceDirector newObject = (ExecutionChoiceDirector) super.clone(workspace);
088        newObject._addedDirectors = new LinkedList<Director>();
089        return newObject;
090    }
091    
092    /** Read the control token input, transfer input tokens,
093     *  and invoke prefire() of the selected refinement.
094     *
095     *  @exception IllegalActionException If there is no director,
096     *   or if the director's prefire() method throws it, or if this actor
097     *   is not opaque.
098     */
099    @Override
100    public boolean prefire() throws IllegalActionException {
101        if (_debugging) {
102            _debug("Calling prefire()");
103        }
104
105        try {
106            _workspace.getReadAccess();
107            //super.prefire();
108
109            Case container = (Case) getContainer();
110            // Read from port parameters, including the control port.
111            Iterator<PortParameter> portParameters = container.attributeList(
112                    PortParameter.class).iterator();
113            while (portParameters.hasNext()) {
114                PortParameter portParameter = (PortParameter) portParameters
115                        .next();
116                portParameter.update();
117            }
118
119            String controlValue;
120            Token controlToken = container.control.getToken();
121            // If it's a string, use stringValue() otherwise there
122            // are quotes around the string.
123            if (controlToken instanceof StringToken) {
124                controlValue = ((StringToken) controlToken).stringValue();
125            } else {
126                controlValue = controlToken.toString();
127            }
128
129            ExecutionChoice choice = (ExecutionChoice)container;
130            
131            Refinement refinement = (Refinement) container.getEntity(controlValue);
132            
133            // make sure we found the refinement.
134            if(refinement == null) {
135                throw new IllegalActionException(choice, "Could not find execution choice called \"" +
136                                controlValue + "\"");
137            }
138            
139            // NOTE: the control value in ExecutionChoice is prevented from being
140            // set to something other than a refinement, so this check is not necessary.
141            /*
142            if (!(refinement instanceof Refinement)) {
143                refinement = choice._getDefaultRefinement();
144            }
145            */
146            choice._setCurrentRefinement(refinement);
147
148            // Transfer input tokens.
149            for (IOPort port : (List<IOPort>)choice.inputPortList()) {
150                
151                if(_stopRequested) {
152                    break;
153                }
154                
155                if (!(port instanceof ParameterPort)) {
156                    Receiver[][] insideReceivers = port.deepGetReceivers();
157                    for (int i = 0; i < insideReceivers.length; i++) {
158                        Token token = null;
159                        if(port.numberOfSources() > 0) {
160                            if (i < port.getWidth() && port.hasToken(i)) {
161                                token = port.get(i);
162                            }
163                        } else if(choice.getPortIOType(port) == ExecutionChoice.IOType.File){
164                            token = ((Parameter)container.getAttribute(port.getName())).getToken();
165                        }
166                        if(token != null) {
167                            if (insideReceivers[i] != null) {
168                                for (int j = 0; j < insideReceivers[i].length; j++) {
169                                    if (insideReceivers[i][j].getContainer()
170                                            .getContainer() == refinement) {
171
172                                        if (_debugging) {
173                                            _debug(new IOPortEvent(port,
174                                                    insideReceivers[i][j]
175                                                            .getContainer(),
176                                                    true, i, false, token));
177                                        }
178
179                                        insideReceivers[i][j].put(token);
180
181                                        if (_debugging) {
182                                            _debug(new IOPortEvent(port,
183                                                    insideReceivers[i][j]
184                                                            .getContainer(),
185                                                    false, i, false, token));
186                                            _debug(getFullName(),
187                                                    "transferring input from "
188                                                            + port.getFullName()
189                                                            + " to "
190                                                            + (insideReceivers[i][j])
191                                                                    .getContainer()
192                                                                    .getFullName());
193                                        }
194                                    }
195                                }
196                            }
197                        }
198                    }
199                }
200            }
201
202            if (_stopRequested) {
203                return false;
204            }
205            if (_debugging) {
206                _debug(new FiringEvent(this, refinement,
207                        FiringEvent.BEFORE_PREFIRE));
208            }
209            boolean result = refinement.prefire();
210            if (_debugging) {
211                _debug(new FiringEvent(this, refinement,
212                        FiringEvent.AFTER_PREFIRE));
213            }
214            return result;
215        } finally {
216            _workspace.doneReading();
217        }
218    }
219    
220    /** Add DDF director to any refinements that have no directors. */
221    @Override
222    public void preinitialize() throws IllegalActionException {
223                
224        Case container = (Case) getContainer();
225        final List<Refinement> refinements = container.entityList(Refinement.class);
226        for(Refinement refinement : refinements) {
227                if(!refinement.isOpaque()) {
228                        //System.out.println("adding ddf to " + refinement.getName());
229                        DDFDirector director;
230                                try {
231                                        director = new DDFDirector(refinement, "DDF Director");
232                                } catch (NameDuplicationException e) {
233                                        throw new IllegalActionException(refinement, e,
234                                                        "Error adding DDF director in choice " + refinement.getName());
235                                }
236                                director.setPersistent(false);
237                        director.runUntilDeadlockInOneIteration.setToken(BooleanToken.TRUE);
238                        _addedDirectors.add(director);
239                }
240        }
241                
242        super.preinitialize();
243    }
244    
245    /** Remove all DDF directors that were added to refinements in preinitialize(). */
246    @Override
247    public void wrapup() throws IllegalActionException {
248
249        super.wrapup();
250        
251        for(Director director : _addedDirectors) {
252                try {
253                                //System.out.println("removing ddf from " + director.getContainer().getName());
254                        director.setContainer(null);
255                        } catch (NameDuplicationException e) {
256                                throw new IllegalActionException(director.getContainer(), e,
257                                                "Error removing DDF director in choice " +
258                                                director.getContainer().getName());
259                        }
260        }
261        _addedDirectors.clear();
262
263    }
264
265    /** Transfer data from output ports in an ExecutionChoice actor. The port
266     * is a MultiComposite port that is connected (mirrored) to output ports
267     * inside each of the refinements in the ExecutionChoice actor. If the
268     * inside port has inputs, then transfer the tokens as usual. Otherwise,
269     * if the IOType of the port is File, transfer the value of the parameter
270     * with the same name as the port.
271     *
272     * @exception IllegalActionException If the port is not an opaque output port.
273     * @param port The port to transfer tokens from.
274     * @return True if the port has an inside token that was successfully
275     * transferred. Otherwise return false (or throw an exception).
276     */
277    @Override
278    protected boolean _transferOutputs(IOPort port) throws IllegalActionException {
279       
280        // see if the mirrored port in the refinement has inputs
281
282        // TODO check only current refinement?
283        boolean isConnected = false;
284        List<IOPort> insidePorts = port.insideSourcePortList();
285        for(IOPort insidePort : insidePorts) {
286            // see if the RefinementPort is connected to something in the
287            // refinement
288            if(!insidePort.insideSourcePortList().isEmpty()) {
289                isConnected = true;
290                break;
291            }
292        }
293       
294        // if there are inputs, transfer as usual
295        if (isConnected) {
296            return super._transferOutputs(port);
297        } else if(((ExecutionChoice) port.getContainer()).getPortIOType(port) == ExecutionChoice.IOType.File) {
298
299            // true once we write a token to the port
300            boolean result = false;
301    
302            // get the container's parameter with the same name
303            // as the port's display name.
304            final NamedObj namedObj = getContainer();
305            final String portName = port.getDisplayName();
306            final StringParameter parameter = (StringParameter) namedObj
307                    .getAttribute(portName);
308            // make sure we found it
309            if (parameter == null) {
310                throw new IllegalActionException("Missing parameter for output "
311                        + portName);
312            }
313            
314            // write the token in the parameter to the port
315            final Token token = parameter.getToken();
316            for (int i = 0; i < port.getWidth(); i++) {
317                port.send(i, token);
318                result = true;
319            }
320    
321            return result;
322        }
323        
324        return false;
325    }
326    
327    /** A list of directors that were added to refinements in preinitialize(). */
328    private List<Director> _addedDirectors = new LinkedList<Director>();
329
330}