001    /*
002     * Copyright (c) 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.metro.tools;
020    
021    import java.io.File;
022    import java.io.FileOutputStream;
023    import java.io.IOException;
024    
025    import net.dpml.tools.tasks.GenericTask;
026    
027    import net.dpml.state.State;
028    import net.dpml.state.StateEncoder;
029    
030    import org.apache.tools.ant.BuildException;
031    
032    /**
033     * Task that handles the creation of an encoded state graph.
034     *
035     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
036     * @version 1.2.0
037     */
038    public class StateTask extends GenericTask
039    {
040        private static final StateEncoder STATE_ENCODER = new StateEncoder();
041        
042        private File m_output;
043        private String m_classname;
044        private StateDataType m_data;
045        
046        StateDataType getData()
047        {
048            if( null == m_data )
049            {
050                m_data = new StateDataType( this, true );
051            }
052            return m_data;
053        }
054        
055       /**
056        * Override the default output destination.
057        *
058        * @param file the overriding destination
059        */
060        public void setDest( File file )
061        {
062            m_output = file;
063        }
064    
065       /**
066        * Override the class as the colocated destination.
067        *
068        * @param classname the classname of the target component.
069        */
070        public void setClass( String classname )
071        {
072            m_classname = classname;
073        }
074    
075       /**
076        * Set the state name.
077        * @param name the cname of the state
078        */
079        public void setName( final String name )
080        {
081            getData().setName( name );
082        }
083        
084       /**
085        * Mark the state as a terminal state.
086        * @param flag true if this is a terminal state
087        */
088        public void setTerminal( final boolean flag )
089        {
090            getData().setTerminal( flag );
091        }
092        
093       /**
094        * Add a substate within the state.
095        * @return the sub-state datatype
096        */
097        public StateDataType createState()
098        {
099            return getData().createState();
100        }
101        
102       /**
103        * Add an operation within this state.
104        * @return the operation datatype
105        */
106        public OperationDataType createOperation()
107        {
108            return getData().createOperation();
109        }
110        
111       /**
112        * Add an interface within this state.
113        * @return the interface datatype
114        */
115        public InterfaceDataType createInterface()
116        {
117            return getData().createInterface();
118        }
119        
120       /**
121        * Add an transition within this state.
122        * @return the operation datatype
123        */
124        public TransitionDataType createTransition()
125        {
126            return getData().createTransition();
127        }
128    
129       /**
130        * Add an trigger to the state.
131        * @return the trigger datatype
132        */
133        public TriggerDataType createTrigger()
134        {
135            return getData().createTrigger();
136        }
137        
138       /**
139        * Execute the task.
140        */
141        public void execute()
142        {
143            File file = getOutputFile();
144            File parent = file.getParentFile();
145            if( !parent.exists() )
146            {
147                parent.mkdirs();
148            }
149            createGraph( file );
150        }
151        
152       /**
153        * Create an encoded state graph.
154        * @param file the output file
155        */
156        public void createGraph( File file )
157        {
158            try
159            {
160                FileOutputStream output = new FileOutputStream( file );
161                try
162                {
163                    State graph = getData().getState();
164                    STATE_ENCODER.export( graph, output );
165                }
166                catch( Exception e )
167                {
168                    throw new BuildException( "State encoding error.", e );
169                }
170                finally
171                {
172                    try
173                    {
174                        output.close();
175                    }
176                    catch( IOException ioe )
177                    {
178                        ioe.printStackTrace();
179                    }
180                }
181            }
182            catch( BuildException e )
183            {
184                throw e;
185            }
186            catch( Exception e )
187            {
188                final String error = 
189                  "Internal error while attempting to build the graph.";
190                throw new BuildException( error, e, getLocation() );
191            }
192        }
193    
194        private File getOutputFile()
195        {
196            if( null != m_output )
197            {
198                return m_output;
199            }
200            else if( null != m_classname )
201            {
202                File classes = getContext().getTargetClassesMainDirectory();
203                String path = m_classname.replace( '.', '/' );
204                String filename = path + ".xgraph";
205                return new File( classes, filename );
206            }
207            else
208            {
209                return getDefaultOutputFile();
210            }
211        }
212        
213       /**
214        * Create and return the part output file. 
215        * @return the part output file
216        */
217        protected File getDefaultOutputFile()
218        {
219            File deliverables = getContext().getTargetDeliverablesDirectory();
220            String type = State.TYPE;
221            String types = type + "s";
222            File dir = new File( deliverables, types );
223            String filename = getContext().getLayoutPath( type );
224            return new File( dir, filename );
225        }
226    }