3. Linux tip-of-the-day: bash environment variables
‣ Set a variable to be read by further terminal process
export GRAILS_HOME=$HOME/local/grails-1.3.7
4. Linux tip-of-the-day: bash environment variables
‣ Set a variable to be read by further terminal process
export GRAILS_HOME=$HOME/local/grails-1.3.7
‣ Prepend the path to give priority:
export PATH=$GRAILS_HOME/bin:$PATH
5. Linux tip-of-the-day: bash environment variables
‣ Set a variable to be read by further terminal process
export GRAILS_HOME=$HOME/local/grails-1.3.7
‣ Prepend the path to give priority:
export PATH=$GRAILS_HOME/bin:$PATH
‣ Variables are not shared among “parallel” consoles
6. Linux tip-of-the-day: bash environment variables
‣ Set a variable to be read by further terminal process
export GRAILS_HOME=$HOME/local/grails-1.3.7
‣ Prepend the path to give priority:
export PATH=$GRAILS_HOME/bin:$PATH
‣ Variables are not shared among “parallel” consoles
‣ To set variable a bash startup, edit either
~/.bashrc
~/.profile
14. The pedestrian one-to-many
‣Message.groovy
Person commiter
‣ Person.groovy
Set<Messages> messages=[]
def addToMessages(msg){
msg.commiter=this
msg.save()
messages.add(msg)
}
‣ And we do not mention
- added messages already has a commiter member
- cascade deletion
52. DataSource.groovy
‣ All database configuration is stored under
grails-app/conf/DataSource.groovy
‣ Global vs environment configuration
dataSource {
pooled = true
driverClassName = "org.hsqldb.jdbcDriver"
username = "sa"
password = ""
}
53. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
54. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
55. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
56. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
57. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
"update"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
58. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
"update"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
60. hsqldb on file
‣ Database is saved in 3 flat files
‣ e.g. devDb.script
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE MESSAGE(ID BIGINT GENERATED ...
CREATE MEMORY TABLE PERSON(ID BIGINT GENERATED ...
ALTER TABLE MESSAGE ADD CONSTRAINT FK38EB0007D6D0B12 FOREIGN
KEY(COMMITER_ID) REFERENCES PERSON(ID)
ALTER TABLE MESSAGE ALTER COLUMN ID RESTART WITH 3
ALTER TABLE PERSON ALTER COLUMN ID RESTART WITH 2
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
SET SCHEMA PUBLIC
INSERT INTO MESSAGE VALUES(1,1,'I''m coming',1)
INSERT INTO MESSAGE VALUES(2,0,'on Jolly Jumper',1)
INSERT INTO PERSON VALUES(1,0,'Luke','lucky_luke',
'lucky.luke@morris.com','2010-05-17 01:18:16.607000000','Lucky')
62. More configuration
‣ All configuration files reside into grails-app/conf
‣ Config.groovy handles much
63. More configuration
‣ All configuration files reside into grails-app/conf
‣ Config.groovy handles much
‣ For example, to set failOnError:true by default on
all .save() calls
grails.gorm.save.failOnError = true
72. Uploading a file
1. a local file with a list of contents convertible into messages
(rss feed with publication update from Scientific American & Nature)
73. Uploading a file
1. a local file with a list of contents convertible into messages
(rss feed with publication update from Scientific American & Nature)
2. file is uploaded through a web page with a form
74. Uploading a file
1. a local file with a list of contents convertible into messages
(rss feed with publication update from Scientific American & Nature)
2. file is uploaded through a web page with a form
3. a controller/action receive data + params
75. Uploading a file
1. a local file with a list of contents convertible into messages
(rss feed with publication update from Scientific American & Nature)
2. file is uploaded through a web page with a form
3. a controller/action receive data + params
4. launch a service action to parse file & insert into database
76. Uploading a file
1. a local file with a list of contents convertible into messages
(rss feed with publication update from Scientific American & Nature)
2. file is uploaded through a web page with a form
3. a controller/action receive data + params
4. launch a service action to parse file & insert into database
83. loadList.gsp
enable the form
to upload file
<g:form controller="message" action="loadList"
method="post”
enctype="multipart/form-data">
<input type="file" name="messagefile"/>
<g:select name="type"
from="${['sciam', 'nature'] }"/>
<input type="submit"/>
</g:form>
form field
with file data
85. MessageController.groovy
def loadList = {
if(!params.type){
// the controller is called without parameter
// thus we just display the form
return
}
}
86. MessageController.groovy
def loadList = {
if(!params.type){
// the controller is called without parameter
// thus we just display the form
return
}
def loaders=[
sciam:new ScientificAmericanMessageLoader(),
nature:new NatureMessageLoader()
]
def loader=loaders[params.type]
}
87. MessageController.groovy
def loadList = {
if(!params.type){
// the controller is called without parameter
// thus we just display the form
return
}
def loaders=[
sciam:new ScientificAmericanMessageLoader(),
nature:new NatureMessageLoader()
]
def loader=loaders[params.type]
def input=request.getFile("messagefile").inputStream
}
88. MessageController.groovy
def loadList = {
if(!params.type){
// the controller is called without parameter
// thus we just display the form
return
}
def loaders=[
sciam:new ScientificAmericanMessageLoader(),
nature:new NatureMessageLoader()
]
def loader=loaders[params.type]
def input=request.getFile("messagefile").inputStream
def n=messageService.loadMessages(loader, input)
}
89. MessageController.groovy
def loadList = {
if(!params.type){
// the controller is called without parameter
// thus we just display the form
return
}
def loaders=[
sciam:new ScientificAmericanMessageLoader(),
nature:new NatureMessageLoader()
]
def loader=loaders[params.type]
def input=request.getFile("messagefile").inputStream
def n=messageService.loadMessages(loader, input)
flash.uploadedMessage=
"file was correctly uploaded with $n entries"
}
105. DataSource.groovy
‣ All database configuration is stored under
grails-app/conf/DataSource.groovy
‣ Global vs environment configuration
dataSource {
pooled = true
driverClassName = "org.hsqldb.jdbcDriver"
username = "sa"
password = ""
}
106. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
107. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
108. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
109. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
110. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
"update"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
111. DataSource.groovy
(cont’d)
environments {
development {
dataSource {
// one of 'create', 'create-drop','update'
dbCreate = "create-drop"
"update"
url = "jdbc:hsqldb:mem:devDB"
"jdbc:hsqldb:file:devDb:devDB"
}
}
test {
//skipped
}
production {
dataSource {
dbCreate = "update"
url = "jdbc:hsqldb:file:prodDb;shutdown=true"
}
}
}
113. hsqldb on file
‣ Database is saved in 3 flat files
‣ e.g. devDb.script
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE MESSAGE(ID BIGINT GENERATED ...
CREATE MEMORY TABLE PERSON(ID BIGINT GENERATED ...
ALTER TABLE MESSAGE ADD CONSTRAINT FK38EB0007D6D0B12 FOREIGN
KEY(COMMITER_ID) REFERENCES PERSON(ID)
ALTER TABLE MESSAGE ALTER COLUMN ID RESTART WITH 3
ALTER TABLE PERSON ALTER COLUMN ID RESTART WITH 2
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
SET SCHEMA PUBLIC
INSERT INTO MESSAGE VALUES(1,1,'I''m coming',1)
INSERT INTO MESSAGE VALUES(2,0,'on Jolly Jumper',1)
INSERT INTO PERSON VALUES(1,0,'Luke','lucky_luke',
'lucky.luke@morris.com','2010-05-17 01:18:16.607000000','Lucky')
115. More configuration
‣ All configuration files reside into grails-app/conf
‣ Config.groovy handles much
116. More configuration
‣ All configuration files reside into grails-app/conf
‣ Config.groovy handles much
‣ For example, to set failOnError:true by default on
all .save() calls
grails.gorm.save.failOnError = true
Editor's Notes
\n
\n
&#x201C;terminal&#x201D; shell session\nno export => variable is not passed to forked process\nbash is not the only shell\ncsh tcsh sh etc... with different notation variations\n
&#x201C;terminal&#x201D; shell session\nno export => variable is not passed to forked process\nbash is not the only shell\ncsh tcsh sh etc... with different notation variations\n
&#x201C;terminal&#x201D; shell session\nno export => variable is not passed to forked process\nbash is not the only shell\ncsh tcsh sh etc... with different notation variations\n
&#x201C;terminal&#x201D; shell session\nno export => variable is not passed to forked process\nbash is not the only shell\ncsh tcsh sh etc... with different notation variations\n
relationship are the heart of the domain architectures\nthe expression of the logic of how your objet are built and depends on each others\n
\n
\n
\n
\n
\n
\n
\n
approximative....\n
approximative....\n
approximative....\n
Grails Objet Relational Mapping\nhide SQL complexity beyond a domain description\n...well to some extent\nDomain self constraints in static constraints={}\n
\n
\n
\n
\n
\n
instead of belongsTo = [user:Person]\nconstraints user(nullable:true)\n
instead of belongsTo = [user:Person]\nconstraints user(nullable:true)\n
\n
\n
\n
\n
\n
cf last time\n
\n
\n
\n
\n
\n
\n
Bean list declaration is symmetrical.\nGORM offers the possibility to put a direction of dependency\n
Tag only have a name, which is a unique constrained property\n
belongs : directions\n
belongs : directions\n
belongs : directions\n
\n
see MessageIntegrationTests / testTags() for more tests and examples\n