Skip to content

Commit

Permalink
Updates for Griffon 0.9.5
Browse files Browse the repository at this point in the history
  • Loading branch information
aalmiray committed Feb 18, 2012
1 parent 7ab06ab commit c724245
Show file tree
Hide file tree
Showing 12 changed files with 223 additions and 94 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
target
5 changes: 3 additions & 2 deletions MybatisGriffonAddon.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

import griffon.core.GriffonApplication
import griffon.plugins.mybatis.MybatisConnector
import griffon.plugins.mybatis.MybatisEnhancer

/**
* @author Andres Almiray
Expand All @@ -33,7 +34,7 @@ class MybatisGriffonAddon {
def types = app.config.griffon?.mybatis?.injectInto ?: ['controller']
if(!types.contains(type)) return
MetaClass mc = app.artifactManager.findGriffonClass(klass).metaClass
MybatisConnector.enhance(mc)
MybatisEnhancer.enhance(mc)
}
]
}
148 changes: 132 additions & 16 deletions MybatisGriffonPlugin.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,30 +18,146 @@
*/
class MybatisGriffonPlugin {
// the plugin version
def version = "0.2"
String version = '0.3'
// the version or versions of Griffon the plugin is designed for
def griffonVersion = '0.9.4 > *'
String griffonVersion = '0.9.5 > *'
// the other plugins this plugin depends on
def dependsOn = [datasource: 0.2]
Map dependsOn = [datasource: '0.3']
// resources that are included in plugin packaging
def pluginIncludes = []
List pluginIncludes = []
// the plugin license
def license = 'Apache Software License 2.0'
String license = 'Apache Software License 2.0'
// Toolkit compatibility. No value means compatible with all
// Valid values are: swing, javafx, swt, pivot, gtk
def toolkits = ['']
List toolkits = []
// Platform compatibility. No value means compatible with all
// Valid values are:
// linux, linux64, windows, windows64, macosx, macosx64, solaris
def platforms = []
List platforms = []
// URL where documentation can be found
String documentation = ''
// URL where source can be found
String source = 'https://github.com/griffon/griffon-mybatis-plugin'

def author = 'Andres Almiray'
def authorEmail = 'aalmiray@users.sourceforge.net'
def title = 'Persistence support via Mybatis'
def description = '''
Persistence support via MyBatis
'''
List authors = [
[
name: 'Andres Almiray',
email: 'aalmiray@yahoo.com'
]
]
String title = 'Mybatis support'
String description = '''
The Mybatis plugin enables lightweight access to datasources using [Mybatis][1].
This plugin does NOT provide domain classes nor dynamic finders like GORM does.
Usage
-----
Upon installation the plugin will generate the following artifacts in `$appdir/griffon-app/conf`:
* DataSource.groovy - contains the datasource and pool definitions. Its format is equal to GORM's requirements.
Additional configuration for this artifact is explained in the [DataSource Plugin][2].
* MybatisConfig.groovy - contains SessionFactory definitions.
* BootstrapMybatis.groovy - defines init/destroy hooks for data to be manipulated during app startup/shutdown.
A new dynamic method named `withSqlSession` will be injected into all controllers,
giving you access to a `org.apache.ibatis.session.SqlSession` object, with which you'll be able
to make calls to the database. Remember to make all database calls off the EDT
otherwise your application may appear unresponsive when doing long computations
inside the EDT.
This method is aware of multiple databases. If no databaseName is specified when calling
it then the default database will be selected. Here are two example usages, the first
queries against the default database while the second queries a database whose name has
been configured as 'internal'
package sample
class SampleController {
def queryAllDatabases = {
withSqlSession { sessionFactoryName, sqlSession -> ... }
withSqlSession('internal') { sessionFactoryName, sqlSession -> ... }
}
}
This method is also accessible to any component through the singleton `griffon.plugins.mybatis.MybatisConnector`.
You can inject these methods to non-artifacts via metaclasses. Simply grab hold of a particular metaclass and call
`MybatisEnhancer.enhance(metaClassInstance, mybatisProviderInstance)`.
Configuration
-------------
### Dynamic method injection
The `withSqlSession()` dynamic method will be added to controllers by default. You can
change this setting by adding a configuration flag in `griffon-app/conf/Config.groovy`
griffon.mybatis.injectInto = ['controller', 'service']
### Events
The following events will be triggered by this addon
* MybatisConnectStart[config, databaseName] - triggered before connecting to the database
* MybatisConnectEnd[databaseName, sessionFactory] - triggered after connecting to the database
* MybatisDisconnectStart[databaseName, sessionFactory] - triggered before disconnecting from the database
* MybatisDisconnectEnd[databaseName] - triggered after disconnecting from the database
### Multiple Databases
The config file `MybatisConfig.groovy` defines a default sessionFactory block. As the name
implies this is the sessionFactory used by default, however you can configure named sessionFactories
by adding a new config block. For example connecting to a database whose name is 'internal'
can be done in this way
// URL to the plugin's documentation
def documentation = 'http://griffon.codehaus.org/Mybatis+Plugin'
sessionFactories {
internal {
someConfigurationProperty = someValue
}
}
This block can be used inside the `environments()` block in the same way as the
default database block is used.
### Example
A trivial sample application can be found at [https://github.com/aalmiray/griffon_sample_apps/tree/master/persistence/mybatis][3]
Scripts
-------
* **create-mybatis-class** - creates a new class along with a Mapper interface and its companion XML Mapper.
Testing
-------
The `withSqlSession()` dynamic method will not be automatically injected during unit testing, because addons are simply not initialized
for this kind of tests. However you can use `MybatisEnhancer.enhance(metaClassInstance, mybatisProviderInstance)` where
`mybatisProviderInstance` is of type `griffon.plugins.mybatis.MybatisProvider`. The contract for this interface looks like this
public interface MybatisProvider {
Object withSqlSession(Closure closure);
Object withSqlSession(String sessionFactoryName, Closure closure);
<T> T withSqlSession(CallableWithArgs<T> callable);
<T> T withSqlSession(String sessionFactoryName, CallableWithArgs<T> callable);
}
It's up to you define how these methods need to be implemented for your tests. For example, here's an implementation that never
fails regardless of the arguments it receives
class MyMybatisProvider implements MybatisProvider {
Object withSqlSession(String sessionFactoryName = 'default', Closure closure) { null }
public <T> T withSqlSession(String sessionFactoryName = 'default', CallableWithArgs<T> callable) { null }
}
This implementation may be used in the following way
class MyServiceTests extends GriffonUnitTestCase {
void testSmokeAndMirrors() {
MyService service = new MyService()
MybatisEnhancer.enhance(service.metaClass, new MyMybatisProvider())
// exercise service methods
}
}
[1]: http://www.mybatis.org/java.html
[2]: /plugin/datasource
[3]: https://github.com/aalmiray/griffon_sample_apps/tree/master/persistence/mybatis
'''
}
6 changes: 3 additions & 3 deletions application.properties
@@ -1,5 +1,5 @@
#Griffon Metadata file
#Tue Aug 02 21:37:48 CEST 2011
app.griffon.version=0.9.4
#Sat Feb 18 22:32:31 CET 2012
app.griffon.version=0.9.5-rc2
app.name=mybatis
plugins.datasource=0.2
plugins.datasource=0.3
6 changes: 3 additions & 3 deletions scripts/CreateMybatisClass.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,10 +17,10 @@
* @author Andres Almiray
*/

includeTargets << griffonScript('_GriffonInit')
includeTargets << griffonScript('_GriffonCreateArtifacts')

target('createMybatisClass': 'Creates a new Mybatis class') {
target(name: 'createMybatisClass', description: 'Creates a new Mybatis class',
prehook: null, posthook: null) {
depends(checkVersion, parseArguments)

ant.mkdir(dir: "${basedir}/src/mybatis")
Expand Down
17 changes: 2 additions & 15 deletions scripts/_Events.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,19 +16,6 @@
/**
* @author Andres Almiray
*/

def eventClosure1 = binding.variables.containsKey('eventSetClasspath') ? eventSetClasspath : {cl->}
eventSetClasspath = { cl ->
eventClosure1(cl)
if(compilingPlugin('mybatis')) return
griffonSettings.dependencyManager.flatDirResolver name: 'griffon-mybatis-plugin', dirs: "${mybatisPluginDir}/addon"
griffonSettings.dependencyManager.addPluginDependency('mybatis', [
conf: 'compile',
name: 'griffon-mybatis-addon',
group: 'org.codehaus.griffon.plugins',
version: mybatisPluginVersion
])
}

eventCompileSourcesStart = {
if(compilingPlugin('mybatis')) return
Expand All @@ -37,7 +24,7 @@ eventCompileSourcesStart = {

eventCompileSourcesEnd = {
if(compilingPlugin('mybatis')) return
ant.copy(todir: classesDirPath) {
ant.copy(todir: projectMainClassesDir) {
fileset(dir: "${basedir}/src/mybatis") {
include(name: '**/*.xml')
}
Expand Down
10 changes: 1 addition & 9 deletions scripts/_Install.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,15 +17,7 @@
* @author Andres Almiray
*/

includeTargets << griffonScript("_GriffonInit")
includeTargets << griffonScript("_GriffonCreateArtifacts")

// check to see if we already have a MybatisGriffonAddon
configText = '''root.'MybatisGriffonAddon'.addon=true'''
if(!(builderConfigFile.text.contains(configText))) {
println 'Adding MybatisGriffonAddon to Builder.groovy'
builderConfigFile.text += '\n' + configText + '\n'
}

argsMap = argsMap ?: [:]
argsMap.skipPackagePrompt = true
Expand Down
25 changes: 0 additions & 25 deletions scripts/_Uninstall.groovy

This file was deleted.

21 changes: 3 additions & 18 deletions src/main/griffon/plugins/mybatis/MybatisConnector.groovy
@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,30 +31,15 @@ import griffon.plugins.datasource.DataSourceConnector
* @author Andres Almiray
*/
@Singleton
final class MybatisConnector {
final class MybatisConnector implements SqlSessionProvider {
private final Set<Class> mappers = [] as LinkedHashSet
private bootstrap

static void enhance(MetaClass mc) {
mc.withSqlSession = {Closure closure ->
SqlSessionFactoryHolder.instance.withSqlSession('default', closure)
}
mc.withSqlSession << {String sessionFactoryName, Closure closure ->
SqlSessionFactoryHolder.instance.withSqlSession(sessionFactoryName, closure)
}
mc.withSqlSession << {CallableWithArgs callable ->
SqlSessionFactoryHolder.instance.withSqlSession('default', callable)
}
mc.withSqlSession << {String sessionFactoryName, CallableWithArgs callable ->
SqlSessionFactoryHolder.instance.withSqlSession(sessionFactoryName, callable)
}
}

Object withSqlSession(String sessionFactoryName = 'default', Closure closure) {
SqlSessionFactoryHolder.instance.withSqlSession(sessionFactoryName, closure)
}

Object withSqlSession(String sessionFactoryName = 'default', CallableWithArgs callable) {
public <T> T withSqlSession(String sessionFactoryName = 'default', CallableWithArgs<T> callable) {
SqlSessionFactoryHolder.instance.withSqlSession(sessionFactoryName, callable)
}

Expand Down
40 changes: 40 additions & 0 deletions src/main/griffon/plugins/mybatis/MybatisEnhancer.groovy
@@ -0,0 +1,40 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package griffon.plugins.mybatis

import griffon.util.CallableWithArgs

/**
* @author Andres Almiray
*/
final class MybatisEnhancer {
private MybatisEnhancer() {}

static void enhance(MetaClass mc, SqlSessionProvider provider = SqlSessionFactoryHolder.instance) {
mc.withSqlSession = {Closure closure ->
provider.withSqlSession('default', closure)
}
mc.withSqlSession << {String sessionFactoryName, Closure closure ->
provider.withSqlSession(sessionFactoryName, closure)
}
mc.withSqlSession << {CallableWithArgs callable ->
provider.instance.withSqlSession('default', callable)
}
mc.withSqlSession << {String sessionFactoryName, CallableWithArgs callable ->
provider.withSqlSession(sessionFactoryName, callable)
}
}
}

0 comments on commit c724245

Please sign in to comment.