001/* Utilities that manipulate a model.
002
003 Copyright (c) 2004-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.lib.hoc;
029
030import java.net.URL;
031
032import ptolemy.actor.CompositeActor;
033import ptolemy.actor.Manager;
034import ptolemy.data.RecordToken;
035import ptolemy.data.Token;
036import ptolemy.data.expr.Variable;
037import ptolemy.kernel.util.Attribute;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.KernelException;
040import ptolemy.kernel.util.NamedObj;
041import ptolemy.kernel.util.Settable;
042import ptolemy.moml.MoMLParser;
043
044///////////////////////////////////////////////////////////////////
045//// ModelUtilities
046
047/**
048 A collection of utilities for manipulating a Ptolemy model.
049 FIXME: Currently there is only one major operation for invoke
050 the execution of a model. We may add more later.
051
052 @author Yang Zhao
053 @version $Id$
054 @since Ptolemy II 4.1
055 @Pt.ProposedRating Yellow (eal)
056 @Pt.AcceptedRating Red (cxh)
057 */
058public class ModelUtilities {
059    /** Instances of this class cannot be created.
060     */
061    private ModelUtilities() {
062    }
063
064    ///////////////////////////////////////////////////////////////////
065    ////                         public methods                    ////
066
067    /**
068     * This method takes a url specifying the model to be execute. The
069     * <i>args</i> argument is a record token that will be used to set
070     * corresponding attributes of the specified model by
071     * naming match, (see _setAttribute() method). The results of
072     * executing the model is returned back by setting the value of some
073     * Attributes. In particular, only Attributes
074     * that have name matches the <i>resultLabels</i> are returned.
075     * The return result is a RecordToken which has the resultLabels as
076     * its field.
077     * @param url The Model url.
078     * @param args A set of attributes of the specified model.
079     * @param resultLabels Labels of the returned result.
080     * @return The execution result.
081     * @exception IllegalActionException If can not parse the url
082     * or failed to execute the model.
083     */
084    public static synchronized RecordToken executeModel(URL url,
085            RecordToken args, String[] resultLabels)
086            throws IllegalActionException {
087        if (url != null) {
088            MoMLParser parser = new MoMLParser();
089            NamedObj model;
090
091            try {
092                model = parser.parse(null, url);
093            } catch (Exception ex) {
094                throw new IllegalActionException(
095                        ex + "Failed to pass the model URL." + url.toString());
096            }
097
098            if (model instanceof CompositeActor) {
099                return executeModel((CompositeActor) model, args, resultLabels);
100            } else {
101                return null;
102            }
103        } else {
104            return null;
105        }
106    }
107
108    /**
109     * This method takes model argument which is type of CompositeActor.
110     * The <i>args</i> argument is a record token that will be used to
111     * set corresponding attributes of the specified model by
112     * naming match, (see _setAttribute() method). The results of
113     * executing the model is returned back by setting the value of some
114     * Attributes. In particular, only Attributes
115     * that have name matches the <i>resultLabels</i> are returned.
116     * The return result is a RecordToken which has the resultLabels as
117     * its field.
118     * @param model The Model.
119     * @param args A set of attributes of the specified model.
120     * @param resultLabels Labels of the returned result.
121     * @return The execution result.
122     * @exception IllegalActionException If failed to execute the model.
123     */
124    public static synchronized RecordToken executeModel(CompositeActor model,
125            RecordToken args, String[] resultLabels)
126            throws IllegalActionException {
127        Manager manager = model.getManager();
128
129        if (manager == null) {
130            //System.out.println("create manager for the model");
131            manager = new Manager(model.workspace(), "Manager");
132            model.setManager(manager);
133        }
134
135        _setAttribute(model, args);
136
137        try {
138            manager.execute();
139        } catch (KernelException ex) {
140            throw new IllegalActionException(ex + "Execution failed.");
141        }
142
143        return _getResult(model, resultLabels);
144    }
145
146    ///////////////////////////////////////////////////////////////////
147    ////                         private methods                   ////
148
149    /** Iterate over the labelSet of the <i>args</i> argument and
150     *  check whether the specified model has Attribute with the
151     *  same name of a label. If so, set the value of the attribute
152     *  to be the value of that record field.
153     *  @exception IllegalActionException If reading the ports or
154     *   setting the parameters causes it.
155     */
156    private static void _setAttribute(CompositeActor model, RecordToken args)
157            throws IllegalActionException {
158        Object[] labels = args.labelSet().toArray();
159        int length = args.length();
160
161        //String[] labels = new String[length];
162        //Token[] values = new Token[length];
163        for (int i = 0; i < length; i++) {
164            String label = (String) labels[i];
165            Attribute attribute = model.getAttribute(label);
166
167            // Use the token directly rather than a string if possible.
168            if (attribute != null) {
169                Token token = args.get(label);
170
171                if (attribute instanceof Variable) {
172                    ((Variable) attribute).setToken(token);
173                } else if (attribute instanceof Settable) {
174                    ((Settable) attribute).setExpression(token.toString());
175                }
176            }
177        }
178    }
179
180    /** Iterate over the resultLabels and
181     *  check whether the specified model has Attribute with the
182     *  same name of a label. If so, get the value of the attribute
183     *  and return a record token with labels equal to resultLabels
184     *  and values equal to the corresponding attribute value.
185     *  @param model The model executed.
186     *  @param resultLabels Labels of the returned result.
187     *  @return The execution result.
188     *  @exception IllegalActionException If reading the ports or
189     *   setting the parameters causes it.
190     */
191    private static RecordToken _getResult(CompositeActor model,
192            String[] resultLabels) throws IllegalActionException {
193        Token[] value = new Token[resultLabels.length];
194
195        for (int i = 0; i < resultLabels.length; i++) {
196            String label = resultLabels[i];
197            Attribute attribute = model.getAttribute(label);
198
199            if (attribute instanceof Variable) {
200                value[i] = ((Variable) attribute).getToken();
201            }
202        }
203
204        return new RecordToken(resultLabels, value);
205    }
206}