GRAILS-1019: Allowing expressions to be used with the 'disabled' attribute for g...
[grails.git] / src / scaffolding / org / codehaus / groovy / grails / scaffolding / DefaultGrailsTemplateGenerator.groovy
blob6c0e3c5a600387fe1a58303effe1e31d39db9874
1 /*
2 * Copyright 2004-2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.codehaus.groovy.grails.scaffolding;
18 import groovy.text.*;
19 import org.apache.commons.logging.Log;
20 import org.springframework.core.io.*
21 import org.apache.commons.logging.LogFactory;
22 import org.codehaus.groovy.grails.commons.GrailsDomainClass;
23 import org.codehaus.groovy.grails.commons.GrailsApplication;
24 import org.codehaus.groovy.grails.scaffolding.GrailsTemplateGenerator;
25 import org.codehaus.groovy.grails.commons.GrailsClassUtils as GCU
26 import org.codehaus.groovy.grails.commons.ApplicationHolder;
27 /**
28 * Default implementation of the generator that generates grails artifacts (controllers, views etc.)
29 * from the domain model
31 * @author Graeme Rocher
32 * @since 09-Feb-2006
34 class DefaultGrailsTemplateGenerator implements GrailsTemplateGenerator {
36 static final Log LOG = LogFactory.getLog(DefaultGrailsTemplateGenerator.class);
38 String basedir = "."
39 boolean overwrite = false
40 def engine = new SimpleTemplateEngine()
41 def ant = new AntBuilder()
42 ResourceLoader resourceLoader
43 Template renderEditorTemplate
45 void setResourceLoader(ResourceLoader rl) {
46 LOG.info "Scaffolding template generator set to use resource loader ${rl}"
47 this.resourceLoader = rl
50 // a closure that uses the type to render the appropriate editor
51 def renderEditor = { property ->
52 def domainClass = property.domainClass
53 def cp = domainClass.constrainedProperties[property.name]
55 if(!renderEditorTemplate) {
56 // create template once for performance
57 def templateText = getTemplateText("renderEditor.template")
58 renderEditorTemplate = engine.createTemplate(templateText)
61 def binding = [property:property,domainClass:domainClass,cp:cp]
62 return renderEditorTemplate.make(binding).toString()
65 public void generateViews(GrailsDomainClass domainClass, String destdir) {
66 if(!destdir)
67 throw new IllegalArgumentException("Argument [destdir] not specified")
69 def viewsDir = new File("${destdir}/grails-app/views/${domainClass.propertyName}")
70 if(!viewsDir.exists())
71 viewsDir.mkdirs()
73 LOG.info("Generating list view for domain class [${domainClass.fullName}]")
74 generateListView(domainClass,viewsDir)
75 LOG.info("Generating show view for domain class [${domainClass.fullName}]")
76 generateShowView(domainClass,viewsDir)
77 LOG.info("Generating edit view for domain class [${domainClass.fullName}]")
78 generateEditView(domainClass,viewsDir)
79 LOG.info("Generating create view for domain class [${domainClass.fullName}]")
80 generateCreateView(domainClass,viewsDir)
83 public void generateController(GrailsDomainClass domainClass, String destdir) {
84 if(!destdir)
85 throw new IllegalArgumentException("Argument [destdir] not specified")
87 if(domainClass) {
88 def fullName = domainClass.fullName
89 def pkg = ""
90 def pos = fullName.lastIndexOf('.')
91 if (pos != -1) {
92 // Package name with trailing '.'
93 pkg = fullName[0..pos]
96 def destFile = new File("${destdir}/grails-app/controllers/${pkg.replace('.' as char, '/' as char)}${domainClass.shortName}Controller.groovy")
97 if(canWrite(destFile)) {
98 destFile.parentFile.mkdirs()
100 destFile.withWriter { w ->
101 generateController(domainClass, w)
104 LOG.info("Controller generated at ${destFile}")
109 private generateListView(domainClass, destDir) {
110 def listFile = new File("${destDir}/list.gsp")
111 if(canWrite(listFile)) {
112 listFile.withWriter { w ->
113 generateView(domainClass, "list", w)
115 LOG.info("list view generated at ${listFile.absolutePath}")
119 private generateShowView(domainClass,destDir) {
120 def showFile = new File("${destDir}/show.gsp")
121 if(canWrite(showFile)) {
122 showFile.withWriter { w ->
123 generateView(domainClass, "show", w)
125 LOG.info("Show view generated at ${showFile.absolutePath}")
129 private generateEditView(domainClass,destDir) {
130 def editFile = new File("${destDir}/edit.gsp")
131 if(canWrite(editFile)) {
132 editFile.withWriter { w ->
133 generateView(domainClass, "edit", w)
135 LOG.info("Edit view generated at ${editFile.absolutePath}")
139 private generateCreateView(domainClass,destDir) {
140 def createFile = new File("${destDir}/create.gsp")
141 if(canWrite(createFile)) {
143 createFile.withWriter { w ->
144 generateView(domainClass, "create", w)
146 LOG.info("Create view generated at ${createFile.absolutePath}")
150 void generateView(GrailsDomainClass domainClass, String viewName, Writer out) {
151 def templateText = getTemplateText("${viewName}.gsp")
153 def t = engine.createTemplate(templateText)
154 def multiPart = domainClass.properties.find{it.type==([] as Byte[]).class || it.type==([] as byte[]).class}
156 def packageName = domainClass.packageName ? "<%@ page import=\"${domainClass.fullName}\" %>" : ""
157 def binding = [ packageName:packageName,
158 domainClass: domainClass,
159 multiPart:multiPart,
160 className:domainClass.shortName,
161 propertyName:domainClass.propertyName,
162 renderEditor:renderEditor,
163 comparator:org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator.class]
165 t.make(binding).writeTo(out)
168 void generateController(GrailsDomainClass domainClass, Writer out) {
169 def templateText = getTemplateText("Controller.groovy")
171 def binding = [ packageName:domainClass.packageName,
172 domainClass:domainClass,
173 className:domainClass.shortName,
174 propertyName:domainClass.propertyName,
175 comparator:org.codehaus.groovy.grails.scaffolding.DomainClassPropertyComparator.class]
177 def t = engine.createTemplate(templateText)
178 t.make(binding).writeTo(out)
181 private canWrite(testFile) {
182 if(!overwrite && testFile.exists()) {
183 try {
184 ant.input(message: "File ${testFile} already exists. Overwrite?", "y,n,a", addproperty: "overwrite.${testFile.name}")
185 overwrite = (ant.antProject.properties."overwrite.${testFile.name}" == "a") ? true : overwrite
186 return overwrite || ((ant.antProject.properties."overwrite.${testFile.name}" == "y") ? true : false)
187 } catch (Exception e) {
188 // failure to read from standard in means we're probably running from an automation tool like a build server
189 return true
192 return true
195 private getTemplateText(String template) {
196 def application = ApplicationHolder.getApplication()
197 // first check for presence of template in application
198 if(resourceLoader && application?.warDeployed) {
199 return resourceLoader
200 .getResource("/WEB-INF/templates/scaffolding/${template}")
201 .inputStream
202 .text
204 else {
205 def templateFile = "${basedir}/src/templates/scaffolding/${template}"
206 if (!new File(templateFile).exists()) {
207 // template not found in application, use default template
208 def ant = new AntBuilder()
209 ant.property(environment:"env")
210 def grailsHome = ant.antProject.properties."env.GRAILS_HOME"
211 templateFile = "${grailsHome}/src/grails/templates/scaffolding/${template}"
213 return new File(templateFile).getText()