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
;
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
;
28 * Default implementation of the generator that generates grails artifacts (controllers, views etc.)
29 * from the domain model
31 * @author Graeme Rocher
34 class DefaultGrailsTemplateGenerator
implements GrailsTemplateGenerator
{
36 static final Log LOG
= LogFactory
.getLog(DefaultGrailsTemplateGenerator
.class);
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
) {
67 throw new IllegalArgumentException("Argument [destdir] not specified")
69 def viewsDir
= new File("${destdir}/grails-app/views/${domainClass.propertyName}")
70 if(!viewsDir
.exists())
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
) {
85 throw new IllegalArgumentException("Argument [destdir] not specified")
88 def fullName
= domainClass
.fullName
90 def pos
= fullName
.lastIndexOf('.')
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
,
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()) {
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
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}")
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()