001    /*--------------------------------------------------------------------------+
002    $Id: SimulinkModelBuilder.java 26277 2010-02-18 10:46:58Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed under the Apache License, Version 2.0 (the "License");          |
007    | you may not use this file except in compliance with the License.         |
008    | You may obtain a copy of the License at                                  |
009    |                                                                          |
010    |    http://www.apache.org/licenses/LICENSE-2.0                            |
011    |                                                                          |
012    | Unless required by applicable law or agreed to in writing, software      |
013    | distributed under the License is distributed on an "AS IS" BASIS,        |
014    | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015    | See the License for the specific language governing permissions and      |
016    | limitations under the License.                                           |
017    +--------------------------------------------------------------------------*/
018    package edu.tum.cs.simulink.builder;
019    
020    import static edu.tum.cs.simulink.model.SimulinkConstants.SECTION_Library;
021    import static edu.tum.cs.simulink.model.SimulinkConstants.SECTION_Model;
022    import static edu.tum.cs.simulink.model.SimulinkConstants.SECTION_Stateflow;
023    
024    import java.io.File;
025    import java.io.FileNotFoundException;
026    import java.io.FileReader;
027    import java.util.List;
028    
029    import java_cup.runtime.Symbol;
030    import edu.tum.cs.commons.logging.ILogger;
031    import edu.tum.cs.simulink.model.ParameterizedElement;
032    import edu.tum.cs.simulink.model.SimulinkConstants;
033    import edu.tum.cs.simulink.model.SimulinkModel;
034    
035    /**
036     * Main Simulink/Stateflow model building class.
037     * 
038     * @author deissenb
039     * @author $Author: juergens $
040     * @version $Rev: 26277 $
041     * @levd.rating GREEN Hash: E704F92B0AFA17405410791609277169
042     */
043    public class SimulinkModelBuilder {
044    
045            /** File to parse. */
046            private final File file;
047    
048            /** Logger. */
049            private final ILogger logger;
050    
051            /**
052             * Create mode builder.
053             * 
054             * @param file
055             *            file to parse
056             * @param logger
057             *            logger for reporting anomalies. You may use SimpleLogger here.
058             */
059            public SimulinkModelBuilder(File file, ILogger logger) {
060                    this.file = file;
061                    this.logger = logger;
062            }
063    
064            /**
065             * Build model.
066             * 
067             * @return the model
068             * @throws FileNotFoundException
069             *             if file was not found.
070             * @throws SimulinkModelBuildingException
071             *             if a parsing error occurred.
072             */
073            public SimulinkModel buildModel() throws FileNotFoundException,
074                            SimulinkModelBuildingException {
075                    MDLSection simulinkFile = parseFile();
076    
077                    // get section that holds Simulink model to determine model name and
078                    // type
079                    MDLSection modelSection = getSimulinkModelSection(simulinkFile);
080                    SimulinkModel model = new SimulinkModel(file, modelSection.getName()
081                                    .equals(SECTION_Library));
082                    addParameters(model, modelSection);
083    
084                    // build Stateflow machine first
085                    MDLSection stateflowSection = simulinkFile
086                                    .getFirstSubSection(SECTION_Stateflow);
087                    if (stateflowSection != null) {
088                            new StateflowBuilder(model, logger)
089                                            .buildStateflow(stateflowSection);
090                    }
091    
092                    new SimulinkBuilder(model, logger).buildSimulink(modelSection);
093    
094                    return model;
095            }
096    
097            /**
098             * Determine the section that holds the Simulink model. This may be
099             * {@link SimulinkConstants#SECTION_Model} or
100             * {@link SimulinkConstants#SECTION_Library}</code>.
101             * 
102             * @param simulinkFile
103             *            the Simulink file
104             * @throws SimulinkModelBuildingException
105             *             if no or multiple {@link SimulinkConstants#SECTION_Model}/
106             *             {@link SimulinkConstants#SECTION_Library}</code> were found
107             */
108            private static MDLSection getSimulinkModelSection(MDLSection simulinkFile)
109                            throws SimulinkModelBuildingException {
110                    List<MDLSection> namedBlocks = simulinkFile
111                                    .getSubSections(SECTION_Model);
112    
113                    if (namedBlocks.isEmpty()) {
114                            namedBlocks = simulinkFile.getSubSections(SECTION_Library);
115                    }
116    
117                    if (namedBlocks.isEmpty() || namedBlocks.size() > 1) {
118                            throw new SimulinkModelBuildingException(
119                                            "Model must have exactly one Model or Library block.");
120                    }
121    
122                    return namedBlocks.get(0);
123            }
124    
125            /**
126             * Parse Simulink file.
127             * 
128             * @throws FileNotFoundException
129             *             if file was not found.
130             * @throws SimulinkModelBuildingException
131             *             if an exception occurred during parsing.
132             */
133            private MDLSection parseFile() throws FileNotFoundException,
134                            SimulinkModelBuildingException {
135                    MDLScanner scanner = new MDLScanner(new FileReader(file));
136                    MDLParser parser = new MDLParser(scanner, logger);
137                    Symbol sym;
138                    try {
139                            sym = parser.parse();
140                    } catch (Exception e) {
141                            throw new SimulinkModelBuildingException(e);
142                    }
143                    MDLSection mdlFile = (MDLSection) sym.value;
144                    return mdlFile;
145            }
146    
147            /**
148             * Add all parameters defined in a section to a Simulink block. The
149             * {@link SimulinkConstants#PARAM_Points} parameter is treated specially
150             * here. This parameter stores layout information and this is merged instead
151             * of overwritten. This behavior is required to deal with the hierarchy in
152             * lines caused by branches.
153             */
154            /* package */static void addParameters(ParameterizedElement element,
155                            MDLSection section) {
156                    for (String name : section.getParameterNames()) {
157                            // be smart for some special parameters
158                            if (SimulinkConstants.PARAM_Points.equals(name)) {
159                                    String value = element
160                                                    .getParameter(SimulinkConstants.PARAM_Points);
161                                    String newValue = section
162                                                    .getParameter(SimulinkConstants.PARAM_Points);
163                                    if (value == null) {
164                                            value = newValue;
165                                    } else {
166                                            // prepend value
167                                            value = newValue.substring(0, newValue.length() - 1) + "; "
168                                                            + value.substring(1);
169                                    }
170                                    element.setParameter(SimulinkConstants.PARAM_Points, value);
171                            } else {
172                                    element.setParameter(name, section.getParameter(name));
173                            }
174                    }
175            }
176    
177    }