Creating New Folder And Project Per Entity

Posts   
 
    
Dusty
User
Posts: 24
Joined: 19-Feb-2008
# Posted on: 08-Jan-2010 17:45:23   

I am fairly familiar with the task/template architecture. I have created many custom tasks and templates and also modified/replaced some of the stock tasks and templates. I have been pretty happy with my progress thus far.

I now want to be able to create a new folder and new project for each entity in my current project.

Is there anyway to get a SD.Tasks.Base.CreateAFolder task and a SD.Tasks.SelfServicing.VsNetProjectFileCreator task to run for each entity?

Thanks! simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Jan-2010 11:18:27   

The task performers need to be able to act on 'each entity' and the directory creator task performer doesn't, so you have to create a modified version of that.

The vs.net project creator works on the files in the task cache. every time you add the task to the preset, it will use all files in the task cache. You can clear the task cache by adding to the task xml element: requiresCleanCache="true"

However, it can't work on 'all entities'. Why would you want to do this btw? I can't think of a situation where you would want for every entity a separate folder AND a separate vs.net project file.

in v3, you can do this in the designer btw, by placing every entity in a separate 'group' and the designer will then generate the folders and vs.net projects for you. (so you can create small vs.net projects for the complete llblgen pro project)

Frans Bouma | Lead developer LLBLGen Pro
Dusty
User
Posts: 24
Joined: 19-Feb-2008
# Posted on: 11-Jan-2010 16:22:48   

However, it can't work on 'all entities'. Why would you want to do this btw? I can't think of a situation where you would want for every entity a separate folder AND a separate vs.net project file.

I am attempting to generate search/lookup forms for each entity. My framework loads assemlies on demand and that makes if very easy for me to just drop in a modified assembly on the fly.

I create a separate project for each search form because it simplifies my modification process and also allows for user specific modification and distribution. If a user only needs the customer search form then they only get the Search.Customer.dll.

I currently have to manually create the project for each search form, add required references, create a form inherited from the 'SearchFormBase' class and configure it. I have code snippets and MyGeneration templates that do alot of it for me but I am always looking for more/better ways to be lazy. simple_smile

I may reconsider how I am doing things. Perhaps my assembly per search form is a bit overly complex. disappointed

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 11-Jan-2010 18:18:10   

Ah I see what you mean. Yes I think 1 assembly per form is too fine-grained, as each assembly will slow down the application as it has to be loaded, parsed etc. which can be significant if you have many forms.

Frans Bouma | Lead developer LLBLGen Pro
worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 11-Jun-2010 04:27:25   

I'm trying to generate some views (asp.net mvc) for each entity. So I need (ideally) a folder per entity.

Thought this would be in v3.0 stuck_out_tongue_winking_eye

worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 11-Jun-2010 06:29:59   

Here's the modded DirectoryCreator, a very vanilla implementation. Built with v3.0 sourcecode/references.


////////////////////////////////////////////////////////////////////////////////////////////
// Class / interface definitions for the task performers assembly of LLBLGen Pro.
// (c) 2002-2010 Solutions Design, all rights reserved.
// http://www.llblgen.com
// 
// THIS IS NOT OPEN SOURCE SOFTWARE OF ANY KIND. 
// 
// Designed and developed by Frans Bouma.
///////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using SD.LLBLGen.Pro.ApplicationCore.Exceptions;
using SD.LLBLGen.Pro.GeneratorCore;
using SD.LLBLGen.Pro.ApplicationCore;
using System.Collections.Generic;
using SD.LLBLGen.Pro.ApplicationCore.CodeGenerationMetaData.Tasks;

namespace ShivamTaskPerformers
{
    /// <summary>
    /// Generic directory creator which can be used as a task performer.
    /// The following parameters should be specified:
    /// <ul>
    /// <li>folderToCreate. This is the folder relative to the project destination directory.</li>
    /// <li>failWhenExistent. If set to 'true', a GeneratorAbortException will be thrown when
    /// the directory is already available. Optional. Default: 'false'.</li>
    /// <li>clearWhenExistent. If set to 'true', the directory will be cleared, if it already existed.
    /// Set failWhenExistent to 'false' when using this parameter since failWhenExistent overrules
    /// clearWhenExistent. Optional. Default: 'false'.</li>
    /// </ul>
    /// If no parameters are specified or 'path has not been specified, the task will abort the generator, since
    /// this performer performs a vital task.
    /// </summary>
    public class EntityDirectoryCreator : TaskPerformerBase
    {
        /// <summary>
        /// CTor
        /// </summary>
        public EntityDirectoryCreator()
        {
        }


        /// <summary>
        /// Executes the task which is performed by the implementor of ITaskPerformer. 
        /// The method's result should be stored locally and
        /// the property PerformResult should reflect the result of this method,
        /// when that property is called after the method.
        /// </summary>
        /// <param name="executingGenerator">Reference to the generator process executing the task.</param>
        /// <param name="taskDefinition">The definition of the task which called this perform method</param>
        /// <param name="parameters">Hashtable with <see cref="TaskParameter"/> objects, which forms the list
        /// of parameters for this task.</param>
        /// <remarks>When the perform action of a task fails and PerformResult returns false,
        /// it will be marked as failed in the result of the execution of the tasks. 
        /// The generator will not stop performing other tasks unless a task throws a
        /// <see cref="GeneratorAbortException"/> exception.</remarks>
        /// <exception cref="GeneratorAbortException">When the task determines the generation process should abort. Here, the
        /// method will throw this exception when no parameters are specified or when 'folderToCreate' is not specified as a parameter or
        /// when it should fail when the folder already exists</exception>
        public override void Perform(IGenerator executingGenerator, ITask taskDefinition, Dictionary<string, TaskParameter> parameters)
        {
            this.ActiveTask = taskDefinition;
            this.ExecutingGenerator = executingGenerator;

            if(parameters == null)
            {
                throw new GeneratorAbortException("No parameters have been specified. Aborting DirectoryCreator.", taskDefinition);
            }
            if(parameters.Count <= 0)
            {
                throw new GeneratorAbortException("No parameters have been specified. Aborting DirectoryCreator.", taskDefinition);
            }
            if(!parameters.ContainsKey("folderToCreate"))
            {
                throw new GeneratorAbortException("Mandatory parameter 'folderToCreate' not found. Aborting DirectoryCreator.", taskDefinition);
            }

            bool failWhenExistent=false;
            bool clearWhenExistent=false;
            string value;
            if(parameters.ContainsKey("failWhenExistent"))
            {
                value=parameters["failWhenExistent"].Value;
                failWhenExistent=(value.ToLowerInvariant()=="true");
            }
            if(parameters.ContainsKey("clearWhenExistent"))
            {
                value=parameters["clearWhenExistent"].Value;
                clearWhenExistent=(value.ToLowerInvariant()=="true");
            }
            // clearWhenExistent is overruled by failWhenExistent.
            if(failWhenExistent && clearWhenExistent)
            {
                clearWhenExistent=false;
            }

            string folderToCreate = this.HandleDestinationFolder(parameters["folderToCreate"].Value);
            string fullPath = Path.Combine(executingGenerator.DestinationRootFolder, folderToCreate);
            
            foreach(var entity in executingGenerator.Entities){
                string entityDirectory = fullPath.Replace("[elementName]", entity.Name);

                bool alreadyExists = Directory.Exists(entityDirectory);
                if(alreadyExists && failWhenExistent)
                {
                    // fail.
                    throw new GeneratorAbortException("Folder '" + entityDirectory + "' already exists and 'failWhenExistent' is set true. Aborting DirectoryCreator.", taskDefinition);
                }

                if(!alreadyExists)
                {
                    // create it
                    Directory.CreateDirectory(entityDirectory);
                    this.LogLine("Directory '" + entityDirectory + "' created.", "DirectoryCreator", true, true);
                    this.AddNewLogNode(this.ActiveTask.ElementLogNode, LogNodeType.ActionDescription, "Directory '{0}' created succesfully.", fullPath);
                }
                else
                {
                    if(clearWhenExistent)
                    {
                        Directory.Delete(entityDirectory, true);
                        this.LogLine("Directory '" + entityDirectory + "' and contents deleted.", "DirectoryCreator", true, true);
                        this.AddNewLogNode(this.ActiveTask.ElementLogNode, LogNodeType.ActionDescription, "Directory '{0}' and contents deleted successfully.", entityDirectory);
                    }
                        
                    // re create it
                    Directory.CreateDirectory(entityDirectory);
                    this.LogLine("Directory '" + entityDirectory + "' created/preserved.", "DirectoryCreator", true, true);
                    this.AddNewLogNode(this.ActiveTask.ElementLogNode, LogNodeType.ActionDescription, "Directory '{0}' created/preserved successfully.", entityDirectory);
                }
            }

            // done.
            this.PerformResult=true;
        }
    }
}

And a tasks file:


<?xml version="1.0"?>
<taskGroup xmlns="http://sd/llblgen/pro/taskGroupElementDefinitions.xsd"
        name="Shivam.Tasks" isOptional ="true" 
        description="Stuff">

    <supportedPlatforms/>
    <supportedTemplateGroups/>
    <supportedFrameworks>
        <framework name="LLBLGen Pro Runtime Framework"/>
    </supportedFrameworks>
    <dependencies/>
    <taskGroup name="Shivam.EntityDirectoryCreators" description="Creates a directory for each entity" isOptional="true">
        <task name="Shivam.EntityClassesDirectoryCreator" assemblyFilename="ShivamTaskPerformers.dll" 
           taskPerformerClass="ShivamTaskPerformers.EntityDirectoryCreator" isOptional ="true" description ="Creates the Entities folders">
            <supportedPlatforms/>
            <supportedTemplateGroups/>
            <supportedFrameworks>
                <framework name="LLBLGen Pro Runtime Framework"/>
            </supportedFrameworks>
            <dependencies/>
            <parameters>
                <parameter name="folderToCreate" defaultValue="[driverShortName]\EntityClasses" isOptional="false" description="The folder to create"/>
                <parameter name="failWhenExistent" defaultValue="false" isOptional="true" description="Flag to signal what to do when the folder already exists. Overrules clearWhenExistent" valueType="boolean"/>
                <parameter name="clearWhenExistent" defaultValue="false" isOptional="true" description="Flag to signal if an existing folder has to be cleared first. Overruled by failWhenExistent" valueType="boolean"/>
            </parameters>
        </task>
    </taskGroup>
</taskGroup>


Attachments
Filename File size Added on Approval
ShivamTaskPerformers.dll 7,168 11-Jun-2010 06:30.44 Approved
Shivam.Tasks.Generic.tasks 1,505 11-Jun-2010 06:31.12 Approved
daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 11-Jun-2010 06:36:13   

Thanks for sharing Sam.

David Elizondo | LLBLGen Support Team
worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 11-Jun-2010 06:47:39   

Sadly the code emitter still outputs only to a single folder.

It seems the most ideal hook is CodeGenerationEngineBase.EmitOutputToFile which accepts a file name.

If it were virtual it could be easily overridden, it's file name modified and then the base method called.

Going to try overriding CallTemplateEmitter. My hope is the passed in outputWriter doesn't already have anything in it at that point (and that this method does what I think it does). Could then dispose of that outputWriter and make a new one.

worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 11-Jun-2010 08:07:55   

Success! Note I wouldn't use this with anything other than emitting entities. I've probably broken bits of it that support other things (like stored procs, or views etc.).

It will replace [elementName] in the filename and the directory name. Not that the original directory path (with [elementName] in the path) still gets created and empty files get written to it. You can delete them later... or you modify the below code to do it.

Relevants changes are to CallTemplateEmitter and the end of the Perform method. One field has been added.


////////////////////////////////////////////////////////////////////////////////////////////
// Class / interface definitions for the task performers assembly of LLBLGen Pro.
// (c) 2002-2010 Solutions Design, all rights reserved.
// http://www.llblgen.com
// 
// THIS IS NOT OPEN SOURCE SOFTWARE OF ANY KIND. 
// 
// Designed and developed by Frans Bouma.
///////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using SD.LLBLGen.Pro.ApplicationCore.Exceptions;
using SD.LLBLGen.Pro.Core;
using SD.LLBLGen.Pro.GeneratorCore;
using SD.LLBLGen.Pro.ApplicationCore;
using SD.LLBLGen.Pro.ApplicationCore.CodeGenerationMetaData.Templates;
using SD.LLBLGen.Pro.TDLInterpreter;
using SD.LLBLGen.Pro.TDLParser;
using SD.LLBLGen.Pro.ApplicationCore.EntityModel;
using SD.LLBLGen.Pro.ApplicationCore.StoredProcedureCalls;
using SD.LLBLGen.Pro.ApplicationCore.EntityModel.TypedLists;
using SD.LLBLGen.Pro.ApplicationCore.TypedViews;

using SD.LLBLGen.Pro.LptParser;
using SD.LLBLGen.Pro.ApplicationCore.CodeGenerationMetaData.Tasks;
using System.Collections.Generic;

namespace ShivamTaskPerformers
{
    /// <summary>
    /// Generic Code emitter. It will parse the specified template and will then call the interpreter
    /// for each element (f.e. entities), as specified in the parameters, in the project to interpret the parse result with the current 
    /// element set as current scope, if applicable, or an empty scope.
    /// It will open a new file for each file to output in the directory specified and the associated StreamWriter is passed to the interpreter.
    /// If the file already exists, and the file is readonly, the element is skipped. It re-uses an already created TDLParser object. It checks the cache 
    /// if it contains a key 'tdlParser'. If so, it assumes the object with that key is a usable TDLParser object.
    /// The following parameters can be specified.
    /// <ul>
    /// <li>destinationFolder. This is the folder relative to the project destination folder where the entity related file should be stored
    /// The ProjectFileCreator recognizes the following placeholders and will replace them with the related data element:
    ///     <ul>
    ///         <li>[dbgenericSubFolder]. This will be replaced by the value specified in the project properties for AdapterDbGenericSubFolderName. Adapter specific</li>
    ///         <li>[dbspecificSubFolder]. This will be replaced by the value specified in the project properties for AdapterDbSpecificSubFolderName. Adapter specific</li>
    ///     </ul>
    /// </li>
    /// <li>filenameFormat. This is a format specifier for the output filename to use. The CodeEmitter recognizes the following placeholders 
    /// and will replace them with the related data element:
    ///     <ul>
    ///         <li>[elementName]. This will be replaced by the name of the current element, be it the name of the current entity, typed list, 
    ///             stored procedure call or typed view.</li>
    ///         <li>[extension]. This will be replaced by the fileExtension value specified in the template config file.</li>
    ///     </ul>
    /// </li>
    /// <li>templateID. This is the template ID of the template to load and use for code emitting. When the templateID specified is 
    /// not found in the template bindings, the task is skipped and an error is logged.</li>
    /// <li>templateIsOptional. This optional parameter is a boolean flag which signals the task performer to report a missing template ID as an error (false, default) 
    /// or as a normal description (true). Used on tasks which are optional for certain databases, like stored procedure call class generation tasks.</li>
    /// <li>failWhenExistent. If the target file already exist, and this parameter is set to true, the CodeEmitter will skip generating code for that file.
    /// If this parameter is omitted, and a file is readonly, the CodeEmitter will simply skip 
    /// generating code for that file. Optional, default: 'false'.</li>
    /// <li>emitType. This is the type of code emitting the CodeEmitter will perform. Based on the value of this parameter, 
    /// the codeEmitter will walk a given set of elements in the project or will simply execute the specified template without 
    /// walking a set of elements. The following values can be specified as types:
    ///     <ul>
    ///         <li>allEntities. The code emitter will walk all entities defined in the project and will for each entity execute the 
    ///         template specified. elementName in filenameFormat will be replaced by the name of the entity.</li>
    ///         <li>allTypedLists. The code emitter will walk all typedlists defined in the project and will for each typed list execute 
    ///         the template specified. elementName in filenameFormat will be replaced by the name of the typed list.</li>
    ///         <li>allTypedViews. The code emitter will walk all typed views defined in the project and will for each typed view execute 
    ///         the template specified. elementName in filenameFormat will be replaced by the name of the typed view.</li>
    ///         <li>allValueTypes. The engine will walk all value types defined in the project and will for each value type execute
    ///          the template specified. elementName in filenameFormat will be replaced by the name of the valuetype</li>
    ///         <li>actionSPCalls. The code emitter will use the specified template to emit a class for all action stored procedure calls. [elementname] is 
    ///         ignored in filenameFormat.</li>
    ///         <li>retrievalSPCalls.  The code emitter will use the specified template to emit a class for all retrieval stored procedure calls. 
    ///         [elementname] is ignored in filenameFormat.</li>
    ///         <li>generic. The code emitter will simply use the specified template and the current project and generate code. The statements in the 
    ///         template are executed for the project, no elements inside the project are used as a set to execute the template multiple times for 
    ///         multiple files. A single file is the result. [elementname] is ignored in filenameFormat.</li>
    ///     </ul>
    /// </li>
    /// <li>templateBindingDefinitionName. The name of the templatebindings to use for finding the binding for the templateID specified. Optional. Should be
    /// specified only if a very specific templateid binding has to be selected, despite the order of the templatebindings.
    /// </li>
    ///     <li>elementFilter. This filter will accept the body of a lambda for filtering in string format, according to the DynamicQuery example for C#, 
    ///      shipped with VS.NET. The filter is used to filter elements in the set to process. Example "Fields.Count > 0", which can be used to 
    ///         allow only entities which have fields. Optional, default: empty (all elements in the input set are processed)</li>
    /// </ul>
    /// </summary>
    public class CodeEmitter : CodeGenerationEngineBase
    {
        #region Class Member Declarations
        private Interpreter _interpreterToUse;
        #endregion

        /// <summary>
        /// CTor
        /// </summary>
        public CodeEmitter()
        {
            this.EncodingToUse = Encoding.Unicode;
        }


        /// <summary>
        /// Executes the task which is performed by the implementor of ITaskPerformer. 
        /// It assumes there are no parameters. The method's result should be stored locally and
        /// the property PerformResult should reflect the result of this method,
        /// when that property is called after the method.
        /// </summary>
        /// <param name="executingGenerator">Reference to the generator process executing the task.</param>
        /// <param name="taskDefinition">The definition of the task which called this perform method</param>
        /// <remarks>When the perform action of a task fails and PerformResult returns false,
        /// it will be marked as failed in the result of the execution of the tasks. 
        /// The generator will not stop performing other tasks unless a task throws a
        /// <see cref="GeneratorAbortException"/> exception.</remarks>
        /// <exception cref="GeneratorAbortException">When the task determines the generation process should abort. Here, the
        /// method will throw this exception when no parameters are specified or when 'folderToCreate' is not specified as a parameter or
        /// when it should fail when the folder already exists</exception>
        public override void Perform(IGenerator executingGenerator, ITask taskDefinition)
        {
            throw new GeneratorAbortException("No parameters have been specified. Aborting generator.", taskDefinition);
        }


        /// <summary>
        /// Executes the task which is performed by the implementor of ITaskPerformer.
        /// The method's result should be stored locally and
        /// the property PerformResult should reflect the result of this method,
        /// when that property is called after the method.
        /// </summary>
        /// <param name="executingGenerator">Reference to the generator process executing the task.</param>
        /// <param name="taskDefinition">The definition of the task which called this perform method</param>
        /// <param name="parameters">The parameters.</param>
        /// <remarks>When the perform action of a task fails and PerformResult returns false,
        /// it will be marked as failed in the result of the execution of the tasks.
        /// The generator will not stop performing other tasks unless a task throws a
        /// <see cref="GeneratorAbortException"/> exception.</remarks>
        /// <exception cref="GeneratorAbortException">When the task determines the generation process should abort. Here, the
        /// method will throw this exception when no parameters are specified or when 'folderToCreate' is not specified as a parameter or
        /// when it should fail when the folder already exists</exception>
        public override void Perform(IGenerator executingGenerator, ITask taskDefinition, Dictionary<string, TaskParameter> parameters)
        {
            this.ActiveTask = taskDefinition;
            this.ExecutingGenerator = executingGenerator;

            if(parameters==null)
            {
                throw new GeneratorAbortException("No parameters have been specified. Aborting generator.", taskDefinition);
            }

            if(parameters.Count <= 0)
            {
                throw new GeneratorAbortException("No parameters have been specified. Aborting generator.", taskDefinition);
            }

            if(!parameters.ContainsKey("destinationFolder"))
            {
                throw new GeneratorAbortException("Mandatory parameter 'destinationFolder' not found. Aborting generator.", taskDefinition);
            }

            if(!parameters.ContainsKey("filenameFormat"))
            {
                throw new GeneratorAbortException("Mandatory parameter 'filenameFormat' not found. Aborting generator.", taskDefinition);
            }

            if(!parameters.ContainsKey("templateID"))
            {
                throw new GeneratorAbortException("Mandatory parameter 'templateID' not found. Aborting generator.", taskDefinition);
            }

            if(!parameters.ContainsKey("emitType"))
            {
                throw new GeneratorAbortException("Mandatory parameter 'emitType' not found. Aborting generator.", taskDefinition);
            }

            string filenameFormat = parameters["filenameFormat"].Value;
            string templateID = parameters["templateID"].Value;
            string emitTypeSpecified = parameters["emitType"].Value;

            bool failWhenExistent=false;
            bool templateIsOptional = false;
            string value;
            if(parameters.ContainsKey("failWhenExistent"))
            {
                value=parameters["failWhenExistent"].Value;
                failWhenExistent=(value.ToLowerInvariant()=="true");
            }
            if(parameters.ContainsKey("templateIsOptional"))
            {
                value = parameters["templateIsOptional"].Value;
                templateIsOptional = (value.ToLowerInvariant() == "true");
            }
            string templateBindingDefinitionName = string.Empty;
            if( parameters.ContainsKey( "templateBindingDefinitionName" ) )
            {
                templateBindingDefinitionName = parameters["templateBindingDefinitionName"].Value;
            }
            this.ElementFilterToUse = string.Empty;
            if(parameters.ContainsKey("elementFilter"))
            {
                this.ElementFilterToUse = parameters["elementFilter"].Value;
            }
            string destinationFolder = this.HandleDestinationFolder(parameters["destinationFolder"].Value);
            string fullPath = Path.Combine(executingGenerator.DestinationRootFolder, destinationFolder);
            EmitType emitTypeToPerform = GetEmitTypeToPerform(emitTypeSpecified);
            this.ExecutingGenerator.CreateDestinationFilenamesStoreInCache();

            string templateFileContents;
            bool result = CheckIfTemplateFileContentsExists(templateID, templateBindingDefinitionName, templateIsOptional, out templateFileContents);
            if(!result)
            {
                this.PerformResult = false;
                return;
            }

            CompileLptTemplatesIfNecessary(taskDefinition);
            Parser parserToUse = GetAndInitTDLParserToUse(templateID, templateFileContents);
            // parse template
            List<NonTerminal> parseResult = parserToUse.StartParseProcess();
            CreateAndInitTDLInterpreter(templateID, templateBindingDefinitionName, parseResult);
            this.EncodingToUse = CoreUtils.EncodingTypeToTextEncoding(executingGenerator.ProjectDefinition.Properties.EncodingToUse);

            sharedFileName = fullPath;
            if (!Directory.Exists(fullPath))
                Directory.CreateDirectory(fullPath);
            this.PerformResult = EmitOutput(parameters, fullPath, templateID, null, emitTypeToPerform, filenameFormat, failWhenExistent);

            if (Directory.GetFiles(fullPath).Length == 0)
                Directory.Delete(fullPath);

            // reset progress bar to 1
            executingGenerator.SubTaskProgressInitHandler(1);
        }

        string sharedFileName;

        /// <summary>
        /// Performs the pre emit tasks.
        /// </summary>
        /// <param name="currentElement">The current element.</param>
        /// <param name="emitTypeUsed">The emit type used.</param>
        protected override void PerformPreEmitTasks(object currentElement, EmitType emitTypeUsed)
        {
            _interpreterToUse.ResetInterpreter();
            switch(emitTypeUsed)
            {
                case EmitType.ActionSPCalls:
                case EmitType.RetrievalSPCalls:
                    _interpreterToUse.CurrentSPCall = (SPCallDefinition)currentElement;
                    break;
                case EmitType.AllEntities:
                    _interpreterToUse.CurrentEntity = (EntityDefinition)currentElement;
                    break;
                case EmitType.AllTypedLists:
                    _interpreterToUse.CurrentTypedList = (TypedListDefinition)currentElement;
                    break;
                case EmitType.AllTypedViews:
                    _interpreterToUse.CurrentTypedView = (TypedViewDefinition)currentElement;
                    break;
                case EmitType.AllValueTypes:
                    _interpreterToUse.CurrentValueType = (ValueTypeDefinition)currentElement;
                    break;
            }
        }


        /// <summary>
        /// Gets the name of the task performer.
        /// </summary>
        /// <returns></returns>
        protected override string GetTaskPerformerName()
        {
            return "TDL CodeEmitter";
        }


        /// <summary>
        /// Gets and initializes the TDL interpreter to use.
        /// </summary>
        /// <param name="templateID">The template ID.</param>
        /// <param name="templateBindingDefinitionName">Name of the template binding definition.</param>
        /// <param name="parseResult">The parse result.</param>
        /// <returns></returns>
        private void CreateAndInitTDLInterpreter(string templateID, string templateBindingDefinitionName, List<NonTerminal> parseResult)
        {
            _interpreterToUse = new Interpreter(parseResult, this.ExecutingGenerator);
            _interpreterToUse.LlblgenProVersion = ApplicationConstants.LLBLGenProVersion;
            _interpreterToUse.Entities = this.ExecutingGenerator.Entities;
            _interpreterToUse.TypedLists = this.ExecutingGenerator.TypedLists;
            _interpreterToUse.TypedViews = this.ExecutingGenerator.TypedViews;
            _interpreterToUse.ValueTypes = this.ExecutingGenerator.ValueTypes;
            _interpreterToUse.ActionProcedures = this.ExecutingGenerator.ActionProcedures;
            _interpreterToUse.RetrievalProcedures = this.ExecutingGenerator.RetrievalProcedures;
            _interpreterToUse.TemplateBindingDefinitionName = templateBindingDefinitionName;
            _interpreterToUse.TemplateID = templateID;
        }


        /// <summary>
        /// Gets the TDL parser to use. It re-uses an existing parser from the cache. It inits the parser with the template specified.
        /// </summary>
        /// <param name="templateID">The template ID.</param>
        /// <param name="templateFileContents">The template file contents.</param>
        /// <returns>TDL parser ready to use.</returns>
        private Parser GetAndInitTDLParserToUse(string templateID, string templateFileContents)
        {
            Parser parserToUse;
            if(this.ExecutingGenerator.TaskCache.ContainsKey("tdlParser"))
            {
                parserToUse = (Parser)this.ExecutingGenerator.TaskCache["tdlParser"];
                if(parserToUse==null)
                {
                    parserToUse = new Parser(templateFileContents, templateID, this.ExecutingGenerator);
                    this.ExecutingGenerator.TaskCache["tdlParser"] = parserToUse;
                }
                else
                {
                    parserToUse.StringToParse = templateFileContents;
                }
            }
            else
            {
                parserToUse = new Parser(templateFileContents, templateID, this.ExecutingGenerator);
                this.ExecutingGenerator.TaskCache["tdlParser"] = parserToUse;
            }
            return parserToUse;
        }


        /// <summary>
        /// Checks if there is already a compiled .lpt template assembly in the cache, if not, compile the .lpt templates first, so
        /// lpt include templates will be callable from TDL code.
        /// </summary>
        /// <param name="taskDefinition">The task definition.</param>
        private void CompileLptTemplatesIfNecessary(ITask taskDefinition)
        {
            if(this.ExecutingGenerator.GetCompiledIncludeTemplatesAssemblyFromCache()==null)
            {
                // compile all .lpt templates in a single assembly
                DotNetTemplateEngine lptEngine =new DotNetTemplateEngine(this.ExecutingGenerator);
                lptEngine.CompileForTDLIncludeTemplates(taskDefinition);
            }
        }


        /// <summary>
        /// Calls the template emitter logic to emit code for the template using the input.
        /// </summary>
        /// <typeparam name="TElement">The type of the element.</typeparam>
        /// <param name="compiledTemplatesAssembly">The compiled templates assembly.</param>
        /// <param name="templateID">The template ID.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="outputWriter">The output writer.</param>
        /// <param name="currentElement">The current element.</param>
        protected override void CallTemplateEmitter<TElement>(Assembly compiledTemplatesAssembly, string templateID,
                        Dictionary<string, TaskParameter> parameters, StreamWriter outputWriter, TElement currentElement)
        {
            if (currentElement is EntityDefinition){
                outputWriter.Dispose();
                
                FileStream fs = new FileStream(
                    Path.Combine(sharedFileName.Replace("[elementName]", (currentElement as EntityDefinition).Name),
                        parameters["filenameFormat"].Value.Replace("[elementName]", (currentElement as EntityDefinition).Name)), 
                    FileMode.Create, 
                    FileAccess.Write
                );
                var newWriter = new StreamWriter(fs);
                _interpreterToUse.Interpret(newWriter, this.OriginalFileContents);
                newWriter.Dispose();
            }
            else
                _interpreterToUse.Interpret(outputWriter, this.OriginalFileContents);
        }
    }
}

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Jun-2010 08:20:51   

Thanks again for sharing.