[gradle-1.12] 09/211: upstream import 0.9

Kai-Chung Yan seamlik-guest at moszumanska.debian.org
Wed Jul 1 14:17:48 UTC 2015


This is an automated email from the git hooks/post-receive script.

seamlik-guest pushed a commit to branch master
in repository gradle-1.12.

commit 602fcf55bed131d4af10aca7d1901cb8fd71f56e
Author: Miguel Landaeta <miguel at miguel.cc>
Date:   Mon Dec 20 19:30:33 2010 -0430

    upstream import 0.9
---
 build.gradle                                       |  21 +-
 buildSrc/build.gradle                              |  15 +-
 .../src/main/groovy/org/gradle/build/Git.groovy    |  15 +
 .../main/groovy/org/gradle/build/Install.groovy    |  15 +
 .../main/groovy/org/gradle/build/Version.groovy    |  29 +-
 .../build/docs/AssembleSampleDocsTask.groovy       |  15 +
 .../gradle/build/docs/BuildableDOMCategory.groovy  |  23 +-
 .../groovy/org/gradle/build/docs/DomBuilder.groovy |  30 +-
 .../gradle/build/docs/ExtractSnippetsTask.groovy   |  18 +
 .../build/docs/SampleElementLocationHandler.groovy |  15 +
 .../build/docs/SampleElementValidator.groovy       |  61 +-
 .../build/docs/UserGuideTransformTask.groovy       |  81 ++-
 .../build/docs/XIncludeAwareXmlProvider.groovy     |  30 +-
 .../build/docs/dsl/AssembleDslDocTask.groovy       | 120 ----
 .../org/gradle/build/docs/dsl/ClassDoc.groovy      | 115 ----
 .../gradle/build/docs/dsl/ClassLinkMetaData.java   | 109 +++
 .../org/gradle/build/docs/dsl/ClassMetaData.java   |  62 --
 .../org/gradle/build/docs/dsl/DslModel.groovy      |  43 --
 .../gradle/build/docs/dsl/ExtensionMetaData.groovy |  14 -
 .../build/docs/dsl/ExtractDslMetaDataTask.groovy   | 158 +++--
 .../{PropertyMetaData.java => LinkMetaData.java}   |  27 +-
 .../build/docs/dsl/SourceMetaDataVisitor.java      | 481 +++++++++++++
 .../gradle/build/docs/dsl/TypeNameResolver.java    | 167 +++++
 .../docs/dsl/docbook/AssembleDslDocTask.groovy     | 198 ++++++
 .../build/docs/dsl/docbook/BasicJavadocLexer.java  | 194 ++++++
 .../gradle/build/docs/dsl/docbook/BlockDoc.groovy  |  61 ++
 .../gradle/build/docs/dsl/docbook/ClassDoc.groovy  | 319 +++++++++
 .../build/docs/dsl/docbook/ClassDocRenderer.groovy | 422 ++++++++++++
 .../docs/dsl/docbook/ClassExtensionDoc.groovy      |  47 ++
 .../DefaultGenerationListener.java}                |  27 +-
 .../gradle/build/docs/dsl/docbook/DocComment.java  |  22 +-
 .../build/docs/dsl/docbook/DslDocModel.groovy      |  81 +++
 .../ExtensionMetaData.groovy}                      |  28 +-
 .../ExtraAttributeDoc.groovy}                      |  32 +-
 .../build/docs/dsl/docbook/GenerationListener.java |  22 +-
 .../docs/dsl/docbook/HtmlToXmlJavadocLexer.java    | 103 +++
 .../build/docs/dsl/docbook/JavadocConverter.java   | 745 +++++++++++++++++++++
 .../build/docs/dsl/docbook/JavadocLexer.java       |  47 ++
 .../docs/dsl/docbook/JavadocLinkConverter.java     | 172 +++++
 .../build/docs/dsl/docbook/JavadocScanner.java     | 159 +++++
 .../build/docs/dsl/docbook/LinkRenderer.java       | 120 ++++
 .../gradle/build/docs/dsl/docbook/MethodDoc.groovy |  60 ++
 .../build/docs/dsl/docbook/PropertyDoc.groovy      |  70 ++
 .../gradle/build/docs/dsl/model/ClassMetaData.java | 250 +++++++
 .../build/docs/dsl/model/LanguageElement.java      |  22 +-
 .../build/docs/dsl/model/MethodMetaData.java       | 138 ++++
 .../build/docs/dsl/model/ParameterMetaData.java    |  55 ++
 .../build/docs/dsl/model/PropertyMetaData.java     | 110 +++
 .../gradle/build/docs/dsl/model/TypeContainer.java |  22 +-
 .../gradle/build/docs/dsl/model/TypeMetaData.java  | 186 +++++
 .../org/gradle/build/docs/model/Attachable.java    |  22 +-
 .../build/docs/model/ClassMetaDataRepository.java  |  25 +-
 .../docs/model/SimpleClassMetaDataRepository.java  |  84 +++
 .../docs/dsl/ExtractDslMetaDataTaskTest.groovy     | 641 ++++++++++++++++++
 .../build/docs/dsl/TypeNameResolverTest.groovy     | 178 +++++
 .../gradle/build/docs/dsl/XmlSpecification.groovy  | 129 ++++
 .../docs/dsl/docbook/BasicJavadocLexerTest.groovy  | 169 +++++
 .../docs/dsl/docbook/ClassDocRendererTest.groovy   | 618 +++++++++++++++++
 .../build/docs/dsl/docbook/ClassDocTest.groovy     | 322 +++++++++
 .../docs/dsl/docbook/JavadocConverterTest.groovy   | 371 ++++++++++
 .../dsl/docbook/JavadocLinkConverterTest.groovy    | 182 +++++
 .../build/docs/dsl/docbook/LinkRendererTest.groovy | 145 ++++
 .../build/docs/dsl/model/MethodMetaDataTest.groovy | 130 ++++
 .../docs/dsl/model/ParameterMetaDataTest.groovy}   |  30 +-
 .../docs/dsl/model/PropertyMetaDataTest.groovy     | 102 +++
 .../build/docs/dsl/model/TypeMetaDataTest.groovy   | 183 +++++
 .../model/SimpleClassMetaDataRepositoryTest.groovy |  99 +++
 .../src/test/resources/org/gradle/test/A.groovy    |   4 +
 .../org/gradle/test/GroovyAnnotation.groovy        |   5 +
 .../resources/org/gradle/test/GroovyClass.groovy   |  55 ++
 .../gradle/test/GroovyClassWithConstants.groovy    |  12 +
 .../test/GroovyClassWithFullyQualifiedNames.groovy |  10 +
 .../org/gradle/test/GroovyClassWithImports.groovy  |  10 +
 .../gradle/test/GroovyClassWithInnerTypes.groovy   |  31 +
 .../org/gradle/test/GroovyClassWithMethods.groovy  |  57 ++
 .../test/GroovyClassWithParameterizedTypes.groovy  |  19 +
 .../resources/org/gradle/test/GroovyEnum.groovy    |   5 +
 .../org/gradle/test/GroovyInterface.groovy         |   4 +
 .../test/resources/org/gradle/test/Interface1.java |   4 +
 .../resources/org/gradle/test/Interface2.groovy    |   5 +
 .../resources/org/gradle/test/JavaAnnotation.java  |   4 +
 .../test/resources/org/gradle/test/JavaClass.java  |  69 ++
 .../org/gradle/test/JavaClassWithConstants.java    |  11 +
 .../test/JavaClassWithFullyQualifiedNames.java     |  10 +
 .../org/gradle/test/JavaClassWithImports.java      |  12 +
 .../org/gradle/test/JavaClassWithInnerTypes.java   |  41 ++
 .../org/gradle/test/JavaClassWithMethods.java      |  40 ++
 .../test/JavaClassWithParameterizedTypes.java      |  21 +
 .../test/resources/org/gradle/test/JavaEnum.java   |   5 +
 .../resources/org/gradle/test/JavaInterface.java   |   4 +
 .../gradle/test/JavaInterfaceWithConstants.java    |   6 +
 .../org/gradle/test/sub/SubGroovyClass.groovy      |   4 +
 .../org/gradle/test/sub/SubJavaInterface.java      |   4 +
 .../org/gradle/test/sub2/GroovyInterface.groovy    |   5 +
 config/codenarc.xml                                |   5 +
 gradle.properties                                  |   4 +-
 gradle/codeQuality.gradle                          |  19 +
 src/toplevel/changelog.txt                         |   2 +-
 .../api/plugins/announce/AnnouncePlugin.groovy     |  16 +
 .../api/plugins/announce/internal/Snarl.groovy     |  12 +-
 .../org/gradle/api/plugins/antlr/AntlrTask.java    |  34 +-
 .../org/gradle/api/plugins/quality/Checkstyle.java |  37 +
 .../org/gradle/api/plugins/quality/CodeNarc.java   |  15 +
 .../GroovyCodeQualityPluginConvention.groovy       |  13 +
 .../quality/JavaCodeQualityPluginConvention.groovy |  19 +
 ...CrossVersionCompatibilityIntegrationTest.groovy |  11 +-
 .../gradle/integtests/JUnitIntegrationTest.groovy  |  22 +-
 .../integtests/JUnitTestExecutionResult.groovy     |  13 +-
 .../integtests/UserguideIntegrationTest.groovy     |  52 --
 .../integtests/fixtures/GradleDistribution.java    |   7 +-
 .../fixtures/GradleDistributionExecuter.java       |   3 +-
 .../fixtures/TestClassExecutionResult.java         |   2 +-
 .../integtests/testng/TestNGExecutionResult.groovy |  10 +-
 .../shared/build.gradle                            |   2 +-
 .../canRunJunit3Tests/build.gradle                 |   9 +
 .../src/test/java/org/gradle/Test1.java            |   9 +
 .../test/java/org/gradle/BrokenBeforeAndAfter.java |  23 +
 .../canListenForTestResults/build.gradle           |   2 +-
 .../groovyJdk15Failing/build.gradle                |   2 +-
 .../groovyJdk15Passing/build.gradle                |   2 +-
 .../src/main/groovy/org/gradle/api/Project.java    | 330 +++++----
 .../src/main/groovy/org/gradle/api/Script.java     |  24 +-
 .../src/main/groovy/org/gradle/api/Task.java       |   8 +-
 .../org/gradle/api/artifacts/Configuration.java    |   2 +-
 .../maven/Conf2ScopeMappingContainer.java          |   2 +-
 .../main/groovy/org/gradle/api/file/CopySpec.java  |   2 +-
 .../org/gradle/api/initialization/Settings.java    |   2 +-
 .../AutoCreateDomainObjectContainerDelegate.groovy |   2 +
 .../project/DefaultIsolatedAntBuilder.groovy       |   8 +-
 .../groovy/org/gradle/api/invocation/Gradle.java   |   7 +-
 .../org/gradle/api/tasks/AbstractCopyTask.java     |   4 +
 .../src/main/groovy/org/gradle/api/tasks/Copy.java |  26 +-
 .../main/groovy/org/gradle/api/tasks/Delete.java   |   2 +-
 .../src/main/groovy/org/gradle/api/tasks/Exec.java |  32 +-
 .../groovy/org/gradle/api/tasks/GeneratorTask.java |   2 +-
 .../groovy/org/gradle/api/tasks/GradleBuild.java   |   8 +-
 .../main/groovy/org/gradle/api/tasks/JavaExec.java |  16 +-
 .../src/main/groovy/org/gradle/api/tasks/Sync.java |  16 +-
 .../main/groovy/org/gradle/api/tasks/Upload.java   |  17 +-
 .../org/gradle/api/tasks/VerificationTask.java     |   4 +-
 .../api/tasks/bundling/AbstractArchiveTask.java    |   4 +-
 .../groovy/org/gradle/api/tasks/bundling/Tar.java  |   2 +-
 .../api/tasks/diagnostics/AbstractReportTask.java  |  19 +-
 .../tasks/diagnostics/DependencyReportTask.java    |  26 +-
 .../api/tasks/diagnostics/ProjectReportTask.java   |  51 +-
 .../api/tasks/diagnostics/PropertyReportTask.java  |   3 +-
 .../api/tasks/diagnostics/TaskReportTask.java      |   3 +-
 .../gradle/api/tasks/util/PatternFilterable.java   |   8 +-
 .../org/gradle/api/tasks/util/PatternSet.groovy    |   6 +-
 .../org/gradle/groovy/scripts/BasicScript.groovy   |   6 +-
 .../remote/internal/TcpIncomingConnector.java      |  29 +-
 .../groovy/org/gradle/process/BaseExecSpec.java    |  41 +-
 .../main/groovy/org/gradle/process/ExecSpec.java   |  31 +-
 .../internal/AbstractExecHandleBuilder.java        |   8 +
 .../gradle/process/internal/ExecHandleBuilder.java |   8 +
 .../org/gradle/api/tasks/GradleBuildTest.groovy    |   4 +-
 .../tasks/diagnostics/ProjectReportTaskTest.groovy |  29 +-
 .../LinePerThreadBufferingOutputStreamTest.groovy  |   2 +-
 subprojects/gradle-docs/docs.gradle                |  33 +-
 subprojects/gradle-docs/src/docs/css/base.css      |   4 +-
 subprojects/gradle-docs/src/docs/css/dsl.css       | 102 ++-
 subprojects/gradle-docs/src/docs/css/style.css     |   8 +
 subprojects/gradle-docs/src/docs/dsl/dsl.xml       | 249 +++++++
 .../dsl/org.gradle.api.DefaultTask.xml             |   4 -
 .../src/docs/dsl/org.gradle.api.Project.xml        | 235 +++++++
 .../src/docs/dsl/org.gradle.api.Script.xml         |  76 +++
 .../src/docs/dsl/org.gradle.api.Task.xml           | 103 +++
 .../dsl/org.gradle.api.artifacts.Configuration.xml | 106 +++
 .../dsl/org.gradle.api.initialization.Settings.xml |  52 ++
 .../dsl/org.gradle.api.internal.AbstractTask.xml   |   4 -
 .../dsl/org.gradle.api.internal.ConventionTask.xml |   4 -
 .../docs/dsl/org.gradle.api.invocation.Gradle.xml  |  76 +++
 ...org.gradle.api.plugins.BasePluginConvention.xml |  43 ++
 ...org.gradle.api.plugins.JavaPluginConvention.xml |  65 ++
 ...rg.gradle.api.plugins.MavenPluginConvention.xml |  38 ++
 ...api.plugins.ProjectReportsPluginConvention.xml} |  13 +-
 ...e.api.plugins.ReportingBasePluginConvention.xml |  35 +
 ...org.gradle.api.plugins.WarPluginConvention.xml} |  18 +-
 ....plugins.announce.AnnouncePluginConvention.xml} |  16 +-
 ....plugins.antlr.AntlrSourceVirtualDirectory.xml} |  16 +-
 .../dsl/org.gradle.api.plugins.antlr.AntlrTask.xml |  31 +
 ...adle.api.plugins.jetty.AbstractJettyRunTask.xml |  51 ++
 ...le.api.plugins.jetty.JettyPluginConvention.xml} |  17 +-
 .../dsl/org.gradle.api.plugins.jetty.JettyRun.xml  |  35 +
 .../org.gradle.api.plugins.jetty.JettyRunWar.xml}  |   9 +-
 .../org.gradle.api.plugins.jetty.JettyStop.xml}    |  14 +-
 ...adle.api.plugins.osgi.OsgiPluginConvention.xml} |   7 +-
 .../org.gradle.api.plugins.quality.Checkstyle.xml  |  33 +
 .../org.gradle.api.plugins.quality.CodeNarc.xml    |  29 +
 ...s.quality.GroovyCodeQualityPluginConvention.xml |  39 ++
 ...ins.quality.JavaCodeQualityPluginConvention.xml |  43 ++
 .../dsl/org.gradle.api.tasks.AbstractCopyTask.xml  |  74 ++
 .../org.gradle.api.tasks.Copy.xml}                 |   9 +-
 .../org.gradle.api.tasks.Delete.xml}               |   9 +-
 .../org.gradle.api.tasks.Directory.xml}            |   4 -
 .../src/docs/dsl/org.gradle.api.tasks.Exec.xml     |  67 ++
 .../org.gradle.api.tasks.GeneratorTask.xml}        |  16 +-
 .../org.gradle.api.tasks.GradleBuild.xml}          |  16 +-
 .../dsl/org.gradle.api.tasks.GroovySourceSet.xml   |  16 +-
 .../src/docs/dsl/org.gradle.api.tasks.JavaExec.xml | 122 ++++
 .../org.gradle.api.tasks.ScalaSourceSet.xml}       |  16 +-
 .../docs/dsl/org.gradle.api.tasks.SourceSet.xml    |  74 ++
 .../org.gradle.api.tasks.SourceTask.xml}           |  20 +-
 .../org.gradle.api.tasks.Sync.xml}                 |   9 +-
 .../org.gradle.api.tasks.Upload.xml}               |  19 +-
 .../org.gradle.api.tasks.XmlGeneratorTask.xml}     |   7 +-
 ...adle.api.tasks.bundling.AbstractArchiveTask.xml |  55 ++
 .../org.gradle.api.tasks.bundling.Jar.xml}         |  22 +-
 .../dsl/org.gradle.api.tasks.bundling.Tar.xml      |  12 +-
 .../docs/dsl/org.gradle.api.tasks.bundling.War.xml |  45 ++
 .../dsl/org.gradle.api.tasks.bundling.Zip.xml      |  10 +-
 ...rg.gradle.api.tasks.compile.AbstractCompile.xml |  47 ++
 .../org.gradle.api.tasks.compile.Compile.xml}      |  13 +-
 .../org.gradle.api.tasks.compile.GroovyCompile.xml |  39 ++
 ...e.api.tasks.diagnostics.AbstractReportTask.xml} |   8 +-
 ...api.tasks.diagnostics.DependencyReportTask.xml} |  15 +-
 ...dle.api.tasks.diagnostics.ProjectReportTask.xml |  18 +
 ...e.api.tasks.diagnostics.PropertyReportTask.xml} |   4 -
 ...radle.api.tasks.diagnostics.TaskReportTask.xml} |   4 -
 .../dsl/org.gradle.api.tasks.javadoc.Groovydoc.xml |  78 +++
 .../dsl/org.gradle.api.tasks.javadoc.Javadoc.xml   |  63 ++
 .../org.gradle.api.tasks.scala.ScalaCompile.xml    |  35 +
 .../dsl/org.gradle.api.tasks.scala.ScalaDoc.xml    |  55 ++
 .../docs/dsl/org.gradle.api.tasks.testing.Test.xml | 160 +++++
 .../dsl/org.gradle.api.tasks.wrapper.Wrapper.xml   |  67 ++
 ...org.gradle.plugins.eclipse.EclipseClasspath.xml |  65 ++
 .../org.gradle.plugins.eclipse.EclipseJdt.xml}     |  18 +-
 .../org.gradle.plugins.eclipse.EclipseProject.xml  |  63 ++
 .../dsl/org.gradle.plugins.eclipse.EclipseWtp.xml  |  96 +++
 .../dsl/org.gradle.plugins.idea.IdeaModule.xml     |  90 +++
 .../dsl/org.gradle.plugins.idea.IdeaProject.xml    |  44 ++
 .../org.gradle.plugins.idea.IdeaWorkspace.xml}     |   7 +-
 subprojects/gradle-docs/src/docs/dsl/plugins.xml   |  38 ++
 .../gradle-docs/src/docs/stylesheets/dslHtml.xsl   | 125 +++-
 .../src/docs/userguide/codeQualityPlugin.xml       |   4 +-
 .../gradle-docs/src/docs/userguide/customTasks.xml |   2 +-
 .../gradle-docs/src/docs/userguide/depMngmt.xml    |   8 +-
 .../gradle-docs/src/docs/userguide/dsl/dsl.xml     |  42 --
 .../docs/userguide/dsl/org.gradle.api.Project.xml  |  40 --
 .../dsl/org.gradle.api.tasks.AbstractCopyTask.xml  |  39 --
 .../dsl/org.gradle.plugins.idea.IdeaProject.xml    |  31 -
 .../gradle-docs/src/docs/userguide/dsl/plugins.xml |  13 -
 .../src/docs/userguide/eclipsePlugin.xml           |  20 +-
 .../gradle-docs/src/docs/userguide/ideaPlugin.xml  |  18 +-
 .../src/docs/userguide/installation.xml            |  13 +-
 .../gradle-docs/src/docs/userguide/javaPlugin.xml  |  12 +-
 .../gradle-docs/src/docs/userguide/osgi.xml        |   2 +-
 .../src/docs/userguide/projectReports.xml          |   2 +-
 .../src/docs/userguide/standardPlugins.xml         |   2 +-
 .../src/docs/userguide/standardTasks.xml           | 159 -----
 .../gradle-docs/src/docs/userguide/tutorials.xml   |   2 +-
 .../gradle-docs/src/docs/userguide/userguide.xml   |   3 +-
 .../gradle-docs/src/docs/userguide/warPlugin.xml   |   6 +-
 .../gradle-docs/src/docs/userguide/webTutorial.xml |   2 +-
 .../src/docs/userguide/workingWithFiles.xml        |  14 +-
 .../src/docs/userguide/writingBuildScripts.xml     |   2 +-
 .../src/samples/codeQuality/build.gradle           |   2 +-
 .../samples/groovy/customizedLayout/build.gradle   |   2 +-
 .../samples/groovy/mixedJavaAndGroovy/build.gradle |   2 +-
 .../groovy/multiproject/testproject/build.gradle   |   2 +-
 .../src/test/groovy/org/gradle/VersionTest.groovy  |   4 +-
 .../src/samples/groovy/quickstart/build.gradle     |   2 +-
 .../src/test/groovy/org/gradle/PersonTest.groovy   |   2 +-
 .../gradle-docs/src/samples/osgi/build.gradle      |   2 +-
 .../artifacts/externalDependencies/build.gradle    |   4 +-
 .../externalDependency/build.gradle                |   2 +-
 .../userguide/tutorial/projectReports/build.gradle |   2 +-
 .../userguideOutput/dependencyListReport.out       |   4 +-
 .../samples/userguideOutput/projectListReport.out  |   4 +
 .../gradle/plugins/eclipse/EclipseClasspath.groovy |   6 +-
 .../org/gradle/plugins/eclipse/EclipseJdt.groovy   |  12 +-
 .../gradle/plugins/eclipse/EclipseProject.groovy   |   4 +-
 .../org/gradle/plugins/eclipse/EclipseWtp.groovy   |  26 +-
 .../eclipse/model/internal/ClasspathFactory.groovy |   4 +-
 .../eclipse/model/internal/WtpFactory.groovy       |   4 +-
 .../org/gradle/plugins/idea/IdeaModule.groovy      |  37 +-
 .../org/gradle/plugins/idea/IdeaProject.groovy     |   6 +-
 .../org/gradle/plugins/idea/model/Jdk.groovy       |   2 +-
 subprojects/gradle-jetty/jetty.gradle              |   3 +-
 .../api/plugins/jetty/AbstractJettyRunTask.java    |  22 +
 .../api/plugins/jetty/JettyPluginConvention.java   |   9 +
 .../org/gradle/api/plugins/jetty/JettyRun.java     |  13 +-
 .../org/gradle/api/plugins/jetty/JettyRunWar.java  |   3 +
 .../org/gradle/api/plugins/jetty/JettyStop.java    |   8 +-
 .../java/org/gradle/launcher/DaemonConnector.java  | 151 +++--
 .../main/java/org/gradle/launcher/DaemonMain.java  |  26 +-
 .../gradle/api/plugins/MavenPluginConvention.java  |  27 +-
 ...CrossVersionCompatibilityIntegrationTest.groovy |  47 +-
 .../api/plugins/osgi/OsgiPluginConvention.java     |   7 +-
 .../testing/junit/JUnitTestClassExecuter.java      |   9 +-
 .../junit/JUnitTestResultProcessorAdapter.java     |   6 +-
 .../testing/junit/JUnitXmlReportGenerator.java     |  30 +-
 .../tasks/testing/results/DefaultTestResult.java   |  16 +-
 .../results/StateTrackingTestResultProcessor.java  |   8 +-
 .../tasks/testing/results/TestListenerAdapter.java |   2 +-
 .../org/gradle/api/plugins/BasePlugin.groovy       |   2 +-
 .../gradle/api/plugins/BasePluginConvention.groovy |  21 +
 .../gradle/api/plugins/JavaPluginConvention.groovy |  24 +-
 .../plugins/ProjectReportsPluginConvention.groovy  |   8 +-
 .../gradle/api/plugins/WarPluginConvention.groovy  |   6 +
 .../org/gradle/api/tasks/GroovySourceSet.java      |   5 +-
 .../groovy/org/gradle/api/tasks/SourceSet.java     |  15 +-
 .../org/gradle/api/tasks/bundling/Jar.groovy       |  36 +-
 .../org/gradle/api/tasks/bundling/War.groovy       |  40 +-
 .../gradle/api/tasks/compile/AbstractCompile.java  |  42 +-
 .../api/tasks/compile/AbstractOptions.groovy       |   2 +-
 .../org/gradle/api/tasks/compile/Compile.java      |   7 +-
 .../gradle/api/tasks/compile/CompileOptions.groovy |  56 ++
 .../gradle/api/tasks/compile/ForkOptions.groovy    |  15 +-
 .../gradle/api/tasks/compile/GroovyCompile.java    |  23 +-
 .../org/gradle/api/tasks/javadoc/Groovydoc.java    |  49 +-
 .../org/gradle/api/tasks/javadoc/Javadoc.java      |  49 +-
 .../groovy/org/gradle/api/tasks/testing/Test.java  |  34 +-
 .../org/gradle/api/tasks/testing/TestResult.java   |  20 +-
 .../external/javadoc/MinimalJavadocOptions.java    |  15 +
 .../junit/JUnitTestClassProcessorTest.groovy       |  79 ++-
 .../testing/results/TestListenerAdapterTest.groovy |  72 +-
 .../org/gradle/api/tasks/ScalaSourceSet.java       |  13 +-
 .../org/gradle/api/tasks/scala/ScalaCompile.java   |  11 +-
 .../org/gradle/api/tasks/scala/ScalaDoc.java       |  19 +-
 .../gradle/api/tasks/scala/ScalaDocOptions.groovy  |  13 +
 .../integtests/LiveOutputIntegrationTest.groovy    |   4 +-
 .../groovy/org/gradle/foundation/TestUtility.java  |  22 +-
 .../java/org/gradle/api/tasks/wrapper/Wrapper.java | 241 ++++---
 .../wrapper/internal/WrapperScriptGenerator.java   |  14 +-
 .../org/gradle/api/tasks/wrapper/WrapperTest.java  |  33 +-
 wrapper/gradle-wrapper.properties                  |   2 +-
 327 files changed, 13681 insertions(+), 2053 deletions(-)

diff --git a/build.gradle b/build.gradle
index 3ef888f..d3a3b33 100644
--- a/build.gradle
+++ b/build.gradle
@@ -56,7 +56,7 @@ libraries = [
         commons_lang: 'commons-lang:commons-lang:2.5 at jar',
         dom4j: 'dom4j:dom4j:1.6.1 at jar',
         google_collections: 'com.google.collections:google-collections:1.0 at jar',
-        groovy: 'org.codehaus.groovy:groovy-all:1.7.5 at jar',
+        groovy: 'org.codehaus.groovy:groovy-all:1.7.6 at jar',
         ivy: 'org.apache.ivy:ivy:2.2.0 at jar',
         jaxen: 'jaxen:jaxen:1.1 at jar',
         slf4j_api: 'org.slf4j:slf4j-api:1.6.1 at jar',
@@ -119,22 +119,7 @@ configure(groovyProjects()) {
 }
 
 allprojects {
-    apply plugin: 'code-quality'
-
-    checkstyleConfigDir = "$rootDir/config/checkstyle"
-    checkstyleConfigFileName = new File(checkstyleConfigDir, "checkstyle.xml")
-    codeNarcConfigFileName = "$rootDir/config/codenarc.xml"
-    checkstyleProperties.checkstyleConfigDir = checkstyleConfigDir
-}
-configure(groovyProjects()) {
-    sourceSets.allObjects { sourceSet ->
-        task "${sourceSet.getTaskName('checkstyle', 'groovy')}"(type: Checkstyle) {
-            configFile = new File(checkstyleConfigDir, "checkstyle-groovy.xml")
-            source sourceSet.allGroovy
-            classpath = sourceSet.compileClasspath
-            resultFile = new File(checkstyleResultsDir, "${sourceSet.name}-groovy.xml")
-        }
-    }
+    apply from: "$rootDir/gradle/codeQuality.gradle"
 }
 
 allprojects {
@@ -460,7 +445,7 @@ task releaseArtifacts {
 task release {
     description = 'Builds, tests and uploads the release artifacts'
     group = 'release'
-    dependsOn releaseVersion, tag, releaseArtifacts, testedDists, uploadDists, ':docs:uploadDocs'
+    dependsOn releaseVersion, tag, releaseArtifacts, testedDists, ':docs:uploadDocs'
 }
 
 task wrapper(type: Wrapper, dependsOn: binZip)
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index b8ada1f..cb1b1b7 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -16,6 +16,7 @@
 
 apply plugin: 'groovy'
 apply plugin: 'code-quality'
+apply plugin: 'idea'
 
 repositories {
     mavenRepo(urls: 'http://gradle.artifactoryonline.com/gradle/libs')
@@ -23,16 +24,10 @@ repositories {
 
 dependencies {
     compile gradleApi()
-    // todo Actually it should be only groovy, but without junit we get a strange error. We need to understand this.
+    compile 'com.google.collections:google-collections:1.0 at jar'
     groovy localGroovy()
+    testCompile 'junit:junit:4.8.1 at jar'
+    testCompile 'org.spockframework:spock-core:0.4-groovy-1.7 at jar', 'cglib:cglib-nodep:2.2', 'org.objenesis:objenesis:1.2'
 }
 
-checkstyleConfigDir = "$rootDir/../config/checkstyle"
-checkstyleConfigFileName = new File(checkstyleConfigDir, 'checkstyle.xml')
-codeNarcConfigFileName = "$rootDir/../config/codenarc.xml"
-checkstyleProperties.checkstyleConfigDir = checkstyleConfigDir
-
-task ide(type: Sync) {
-    into file('lib')
-    from { configurations.testRuntime.files(DependencySpecs.type(Type.EXTERNAL)) }
-}
+apply from: '../gradle/codeQuality.gradle'
diff --git a/buildSrc/src/main/groovy/org/gradle/build/Git.groovy b/buildSrc/src/main/groovy/org/gradle/build/Git.groovy
index d9c9fe5..715a195 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/Git.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/Git.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build
 
 import org.gradle.api.Project
diff --git a/buildSrc/src/main/groovy/org/gradle/build/Install.groovy b/buildSrc/src/main/groovy/org/gradle/build/Install.groovy
index f1ab84a..8352798 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/Install.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/Install.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build
 
 import org.gradle.api.tasks.Sync
diff --git a/buildSrc/src/main/groovy/org/gradle/build/Version.groovy b/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
index 9fa1938..b48fa0c 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build
 
 import java.text.SimpleDateFormat
@@ -11,10 +26,7 @@ class Version {
     def Version(project) {
         this.versionNumber = project.nextVersion
         File timestampFile = new File(project.buildDir, 'timestamp.txt')
-        if (!timestampFile.isFile()) {
-            timestampFile.parentFile.mkdirs()
-            timestampFile.createNewFile()
-        } else {
+        if (timestampFile.isFile()) {
             boolean uptodate = true
             def modified = timestampFile.lastModified()
             project.project(':core').fileTree('src/main').visit {fte ->
@@ -26,15 +38,18 @@ class Version {
             if (!uptodate) {
                 timestampFile.setLastModified(new Date().time)
             }
+        } else {
+            timestampFile.parentFile.mkdirs()
+            timestampFile.createNewFile()
         }
         buildTime = new Date(timestampFile.lastModified())
 
         project.gradle.taskGraph.whenReady {graph ->
-            if (!graph.hasTask(':releaseVersion')) {
+            if (graph.hasTask(':releaseVersion')) {
+                release = true
+            } else {
                 this.versionNumber += "-" + getTimestamp()
                 release = false
-            } else {
-                release = true
             }
         }
     }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/AssembleSampleDocsTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/AssembleSampleDocsTask.groovy
index 7fc7365..034703c 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/AssembleSampleDocsTask.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/AssembleSampleDocsTask.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import groovy.xml.DOMBuilder
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
index e106bd0..a188a7f 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import org.w3c.dom.Element
@@ -48,13 +63,19 @@ class BuildableDOMCategory {
         }
     }
 
+    public static addBefore(Element sibling, Node n) {
+        def parent = sibling.parentNode
+        parent.insertBefore(n, sibling)
+    }
+
     public static addAfter(Element sibling, Closure cl) {
         DomBuilder builder = new DomBuilder(sibling.ownerDocument, null)
         cl.delegate = builder
         cl.call()
         def parent = sibling.parentNode
+        def next = sibling.nextSibling
         builder.elements.each { element ->
-            parent.insertBefore(element, sibling.nextSibling)
+            parent.insertBefore(element, next)
         }
     }
 }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
index a1608a8..1f106b6 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
@@ -1,8 +1,24 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import org.w3c.dom.Document
 import org.w3c.dom.Element
 import org.w3c.dom.Node
+import org.w3c.dom.NodeList
 
 class DomBuilder extends BuilderSupport {
     Document document
@@ -60,7 +76,19 @@ class DomBuilder extends BuilderSupport {
     }
 
     def appendChild(Node node) {
-        current.appendChild(document.importNode(node, true))
+        if (!current) {
+            elements << (Element) document.importNode(node, true)
+        } else  {
+            current.appendChild(document.importNode(node, true))
+        }
+    }
+
+    def appendChildren(Iterable<? extends Node> nodes) {
+        nodes.each { appendChild(it) }
+    }
+
+    def appendChildren(NodeList nodes) {
+        nodes.each { appendChild(it) }
     }
 
     def text(String text) {
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/ExtractSnippetsTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/ExtractSnippetsTask.groovy
index fe9e209..f320b60 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/ExtractSnippetsTask.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/ExtractSnippetsTask.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import java.util.regex.Matcher
@@ -7,6 +22,9 @@ import org.gradle.api.tasks.SourceTask
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.file.FileVisitDetails
 
+/**
+ * Produces the snippets files for a set of sample source files.
+ */
 public class ExtractSnippetsTask extends SourceTask {
     @OutputDirectory
     File destDir
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
index 6b89325..3510e8f 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import org.w3c.dom.Element
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementValidator.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementValidator.groovy
index 6f78685..ca0e38c 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementValidator.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementValidator.groovy
@@ -1,15 +1,30 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
 import org.w3c.dom.Element
 
 /**
  * Validates sample element - looks for missing attributes.
- * 
+ *
  * @author Tomek Kaczanowski
  */
 public class SampleElementValidator {
 
-	void validate(Element element) {
+    void validate(Element element) {
         String id = element.'@id'
         if (!id) {
             throw new RuntimeException("No id attribute specified for sample.")
@@ -18,28 +33,30 @@ public class SampleElementValidator {
         if (!srcDir) {
             throw new RuntimeException("No dir attribute specified for sample '$id'.")
         }
-        String title = element.'@title' 
+        String title = element.'@title'
         if (!title) {
-        	throw new RuntimeException("No title attribute specified for sample '$id'.")
+            throw new RuntimeException("No title attribute specified for sample '$id'.")
         }
         element.children().each {Element child ->
-        	if (child.name() == 'sourcefile') {
-        		if (!child.'@file') {
-        			throw new RuntimeException("No file attribute specified for source file in sample '$id'.")
-        		}
-
-        	} else if (child.name() == 'output' || child.name() == 'test') {
-          	  	if (child.'@args' == null) {
-          		  throw new RuntimeException("No args attribute specified for output for sample '$id'.")
-          	  	}
-        	} else if (child.name() == 'layout') {
-        		// nothing, makes no sense to do the validation here, cause I'd have to copy all the logic also
-        	}
-        	else {
-                throw new RuntimeException("Unrecognised sample type ${child.name()} found.")
+            switch (child.name()) {
+                case 'sourcefile':
+                    if (!child.'@file') {
+                        throw new RuntimeException("No file attribute specified for source file in sample '$id'.")
+                    }
+                    break
+                case 'output':
+                case 'test':
+                    if (child.'@args' == null) {
+                        throw new RuntimeException(" No args attribute specified for output for sample '$id'. ")
+                    }
+                    break;
+                case 'layout':
+                    // nothing, makes no sense to do the validation here, cause I'd have to copy all the logic also
+                    break;
+                default:
+                    throw new RuntimeException("Unrecognised sample type ${child.name()} found.")
             }
-        	
-        } 
-	}
-                        
+        }
+    }
+
 }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
index b4a1977..a9840f6 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
@@ -20,13 +20,25 @@ package org.gradle.build.docs
 import groovy.xml.MarkupBuilder
 import groovy.xml.dom.DOMCategory
 import org.gradle.api.DefaultTask
+import org.gradle.api.InvalidUserDataException
 import org.gradle.api.file.FileCollection
+import org.gradle.build.docs.dsl.ClassLinkMetaData
+import org.gradle.build.docs.dsl.LinkMetaData
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import org.gradle.build.docs.model.SimpleClassMetaDataRepository
 import org.w3c.dom.Document
 import org.w3c.dom.Element
 import org.gradle.api.tasks.*
 
 /**
  * Transforms userguide source into docbook, replacing custom xml elements.
+ *
+ * Takes the following as input:
+ * <ul>
+ * <li>A source docbook XML file.</li>
+ * <li>A directory containing the snippets for the samples to be included in the document, as produced by {@link ExtractSnippetsTask}.</li>
+ * <li>Meta-info about the canonical documentation for each class referenced in the document, as produced by {@link org.gradle.build.docs.dsl.docbook.AssembleDslDocTask}.</li>
+ * </ul>
  */
 public class UserGuideTransformTask extends DefaultTask {
     @Input
@@ -36,9 +48,13 @@ public class UserGuideTransformTask extends DefaultTask {
     @Input
     String groovydocUrl
     @Input
+    String dsldocUrl
+    @Input
     String websiteUrl
     @InputFile
     File sourceFile
+    @InputFile
+    File linksFile
     @OutputFile
     File destFile
     @InputDirectory
@@ -88,35 +104,48 @@ public class UserGuideTransformTask extends DefaultTask {
     }
 
     def transformApiLinks(Document doc) {
-        File linksFile = new File(destFile.parentFile, 'links.xml')
-        linksFile.withWriter {Writer writer ->
-            MarkupBuilder xml = new MarkupBuilder(writer)
-            xml.links {
-                doc.documentElement.depthFirst().findAll { it.name() == 'apilink' }.each {Element element ->
-                    String className = element.'@class'
-                    if (!className) {
-                        throw new RuntimeException('No "class" attribute specified for <apilink> element.')
-                    }
-                    String methodName = element.'@method'
-                    String lang = element.'@lang' ?: 'java'
-
-                    Element ulinkElement = doc.createElement('ulink')
-                    String baseUrl = lang == 'groovy' ? groovydocUrl : javadocUrl
-                    String href = "$baseUrl/${className.replace('.', '/')}.html"
-                    ulinkElement.setAttribute('url', href)
+        ClassMetaDataRepository<ClassLinkMetaData> linkRepository = new SimpleClassMetaDataRepository<ClassLinkMetaData>()
+        linkRepository.load(linksFile)
 
-                    Element classNameElement = doc.createElement('classname')
-                    ulinkElement.appendChild(classNameElement)
+        doc.documentElement.depthFirst().findAll { it.name() == 'apilink' }.each {Element element ->
+            String className = element.'@class'
+            if (!className) {
+                throw new RuntimeException('No "class" attribute specified for <apilink> element.')
+            }
+            String methodName = element.'@method'
 
-                    String classBaseName = className.tokenize('.').last()
-                    String linkText = methodName ? "$classBaseName.$methodName()" : classBaseName
-                    classNameElement.appendChild(doc.createTextNode(linkText))
+            def classMetaData = linkRepository.get(className)
+            LinkMetaData linkMetaData = methodName ? classMetaData.getMethod(methodName) : classMetaData.classLink
+            String style = element.'@style' ?: linkMetaData.style.toString().toLowerCase()
 
-                    element.parentNode.replaceChild(ulinkElement, element)
+            Element ulinkElement = doc.createElement('ulink')
 
-                    xml.link(className: className, lang: lang)
-                }
+            String href
+            switch (style) {
+                case 'dsldoc':
+                    href = "$dsldocUrl/${className}.html"
+                    break
+                case 'groovydoc':
+                    href = "$groovydocUrl/${className.replace('.', '/')}.html"
+                    break;
+                case 'javadoc':
+                    href = "$javadocUrl/${className.replace('.', '/')}.html"
+                    break;
+                default:
+                    throw new InvalidUserDataException("Unknown api link style '$style'.")
+            }
+            if (linkMetaData.urlFragment) {
+                href = "$href#$linkMetaData.urlFragment"
             }
+
+            ulinkElement.setAttribute('url', href)
+
+            Element classNameElement = doc.createElement('classname')
+            ulinkElement.appendChild(classNameElement)
+
+            classNameElement.appendChild(doc.createTextNode(linkMetaData.displayName))
+
+            element.parentNode.replaceChild(ulinkElement, element)
         }
     }
 
@@ -227,7 +256,9 @@ public class UserGuideTransformTask extends DefaultTask {
                                 List context = fileName.tokenize('/')
 
                                 int common = 0;
-                                for (;common < stack.size() && common < context.size() && stack[common] == context[common]; common++) { ; }
+                                while (common < stack.size() && common < context.size() && stack[common] == context[common]) {
+                                    common++;
+                                }
                                 stack = stack.subList(0, common)
 
                                 (stack.size() + 1).times { content.append("  ") }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
index cfe9c8e..95db321 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
@@ -1,10 +1,29 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs
 
-import org.w3c.dom.Document
 import javax.xml.parsers.DocumentBuilder
 import javax.xml.parsers.DocumentBuilderFactory
+import javax.xml.transform.OutputKeys
+import javax.xml.transform.Transformer
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.dom.DOMSource
+import javax.xml.transform.stream.StreamResult
+import org.w3c.dom.Document
 import org.w3c.dom.Element
-import groovy.xml.dom.DOMUtil
 
 class XIncludeAwareXmlProvider {
     final Iterable<java.io.File> classpath
@@ -33,7 +52,12 @@ class XIncludeAwareXmlProvider {
 
     void write(File destFile) {
         destFile.withOutputStream {OutputStream stream ->
-            DOMUtil.serialize(root, stream)
+            TransformerFactory factory = TransformerFactory.newInstance();
+            Transformer transformer = factory.newTransformer();
+//                transformer.setOutputProperty(OutputKeys.INDENT, "no");
+            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+            transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml");
+            transformer.transform(new DOMSource(root), new StreamResult(stream));
         }
     }
 
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/AssembleDslDocTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/AssembleDslDocTask.groovy
deleted file mode 100644
index e5b88b0..0000000
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/AssembleDslDocTask.groovy
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.gradle.build.docs.dsl
-
-import org.gradle.api.DefaultTask
-import org.gradle.api.tasks.OutputFile
-import org.gradle.api.tasks.InputFile
-import org.gradle.api.tasks.TaskAction
-import org.gradle.api.file.FileCollection
-import org.gradle.api.tasks.InputFiles
-import org.w3c.dom.Document
-import groovy.xml.dom.DOMCategory
-import org.w3c.dom.Element
-import org.gradle.api.tasks.InputDirectory
-import org.gradle.build.docs.XIncludeAwareXmlProvider
-import org.gradle.build.docs.BuildableDOMCategory
-
-/**
- * Generates the docbook source for the DSL documentation. Uses meta-data extracted from the source, meta-data about the
- * plugins, plus a docbook template file.
- */
-class AssembleDslDocTask extends DefaultTask {
-    @InputFile
-    File sourceFile
-    @InputFile
-    File classMetaDataFile
-    @InputFile
-    File pluginsMetaDataFile
-    @InputDirectory
-    File classDocbookDir
-    @OutputFile
-    File destFile
-    @InputFiles
-    FileCollection classpath;
-
-    @TaskAction
-    def transform() {
-        XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
-        provider.parse(sourceFile)
-        transformDocument(provider.document)
-        provider.write(destFile)
-    }
-
-    private def transformDocument(Document document) {
-        use(DOMCategory) {
-            use(BuildableDOMCategory) {
-                Map<String, ClassMetaData> classes = loadClassMetaData()
-                Map<String, ExtensionMetaData> extensions = loadPluginsMetaData()
-                DslModel model = new DslModel(classDocbookDir, document, classpath, classes, extensions)
-                def root = document.documentElement
-                root.section[0].table.each { Element table ->
-                    insertTypes(table, model)
-                }
-            }
-        }
-    }
-
-    def loadPluginsMetaData() {
-        XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
-        provider.parse(pluginsMetaDataFile)
-        Map<String, ExtensionMetaData> extensions = [:]
-        provider.root.plugin.each { Element plugin ->
-            def description = plugin.'@description'
-            plugin.extends.each { Element e ->
-                def targetClass = e.'@targetClass'
-                def extensionClass = e.'@extensionClass'
-                def extension = extensions[targetClass]
-                if (!extension) {
-                    extension = new ExtensionMetaData(targetClass)
-                    extensions[targetClass] = extension
-                }
-                extension.add(description, extensionClass)
-            }
-        }
-        return extensions
-    }
-
-    def loadClassMetaData() {
-        Map<String, ClassMetaData> classes;
-        classMetaDataFile.withInputStream { InputStream instr ->
-            ObjectInputStream ois = new ObjectInputStream(instr) {
-                @Override protected Class<?> resolveClass(ObjectStreamClass objectStreamClass) {
-                    return AssembleDslDocTask.classLoader.loadClass(objectStreamClass.name)
-                }
-
-            }
-            classes = ois.readObject()
-        }
-        return classes
-    }
-
-    def insertTypes(Element typeTable, DslModel model) {
-        typeTable['@role'] = 'dslTypes'
-        typeTable.addFirst {
-            thead {
-                tr {
-                    td('Type')
-                    td('Description')
-                }
-            }
-        }
-
-        typeTable.tr.each { Element tr ->
-            insertType(tr, model)
-        }
-    }
-
-    def insertType(Element tr, DslModel model) {
-        String className = tr.td[0].text().trim()
-        ClassDoc classDoc = model.getClassDoc(className)
-        Element root = tr.ownerDocument.documentElement
-
-        root << classDoc.classSection
-
-        tr.children = {
-            td {
-                link(linkend: classDoc.id, classDoc.classSimpleName)
-            }
-            td(classDoc.description)
-        }
-    }
-}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassDoc.groovy
deleted file mode 100644
index bbe3a12..0000000
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassDoc.groovy
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.gradle.build.docs.dsl
-
-import org.w3c.dom.Element
-import org.w3c.dom.Node
-
-class ClassDoc {
-    final Element classSection
-    final String className
-    final String id
-    final String classSimpleName
-    final ClassMetaData classMetaData
-
-    ClassDoc(String className, Element classContent, ClassMetaData classMetaData, ExtensionMetaData extensionMetaData, DslModel model) {
-        this.className = className
-        id = className
-        classSimpleName = className.tokenize('.').last()
-        this.classMetaData = classMetaData
-
-        classSection = classContent.ownerDocument.createElement('chapter')
-        classSection['@id'] = id
-        classSection.addFirst {
-            title(classSimpleName)
-        }
-        classContent.childNodes.each { Node n ->
-            classSection << n
-        }
-
-        propertiesTable.tr.each { Element tr ->
-            def cells = tr.td
-            if (cells.size() != 2) {
-                throw new RuntimeException("Expected 2 cells in <tr>, found: $tr")
-            }
-            String propName = cells[0].text().trim()
-            PropertyMetaData property = classMetaData.classProperties[propName]
-            if (!property) {
-                throw new RuntimeException("No metadata for property '$className.$propName'. Available properties: ${classMetaData.classProperties.keySet()}")
-            }
-            String type = property.type
-            tr.td[0].children = { literal(propName) }
-            tr.td[0].addAfter {
-                td {
-                    if (type.startsWith('org.gradle')) {
-                        apilink('class': type)
-                    } else if (type.startsWith('java.lang.') || type.startsWith('java.util.') || type.startsWith('java.io.')) {
-                        classname(type.tokenize('.').last())
-                    } else {
-                        classname(type)
-                    }
-                    if (!property.writeable) {
-                        text(" (read-only)")
-                    }
-                }
-            }
-        }
-
-        if (classMetaData.superClassName) {
-            ClassDoc supertype = model.getClassDoc(classMetaData.superClassName)
-            supertype.propertiesTable.tr.each { Element tr ->
-                propertiesTable << tr
-            }
-            supertype.methodsTable.tr.each { Element tr ->
-                methodsTable << tr
-            }
-        }
-
-        classSection.section[0].addBefore {
-            section {
-                title('API Documentation')
-                para {
-                    apilink('class': className, lang: lang)
-                }
-            }
-        }
-
-        extensionMetaData.extensionClasses.each { Map map ->
-            ClassDoc extensionClassDoc = model.getClassDoc(map.extensionClass)
-            classSection << extensionClassDoc.classSection
-            
-            classSection.lastChild.title[0].text = "${map.plugin} - ${extensionClassDoc.classSimpleName}"
-        }
-    }
-
-    Element getPropertiesTable() {
-        return getSection('Properties').table[0]
-    }
-
-    Element getMethodsTable() {
-        return getSection('Methods').table[0]
-    }
-
-    String getLang() {
-        return classMetaData.groovy ? 'groovy' : 'java'
-    }
-
-    private Element getSection(String title) {
-        def sections = classSection.section.findAll { it.title[0].text().trim() == title }
-        if (sections.size() < 1) {
-            throw new RuntimeException("Docbook content for $className does not contain a '$title' section.")
-        }
-        return sections[0]
-    }
-
-    Element getHasDescription() {
-        def paras = classSection.para
-        return paras.size() > 0 ? paras[0] : null
-    }
-
-    Element getDescription() {
-        def paras = classSection.para
-        if (paras.size() < 1) {
-            throw new RuntimeException("Docbook content for $className does not contain a description paragraph.")
-        }
-        return paras[0]
-    }
-}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassLinkMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassLinkMetaData.java
new file mode 100644
index 0000000..b428a01
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassLinkMetaData.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl;
+
+import org.gradle.build.docs.dsl.model.ClassMetaData;
+import org.gradle.build.docs.dsl.model.MethodMetaData;
+import org.gradle.build.docs.model.Attachable;
+import org.gradle.build.docs.model.ClassMetaDataRepository;
+import org.gradle.util.GUtil;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ClassLinkMetaData implements Serializable, Attachable<ClassLinkMetaData> {
+    private final String className;
+    private final String simpleName;
+    private LinkMetaData.Style style;
+    private final Map<String, MethodLinkMetaData> methods = new HashMap<String, MethodLinkMetaData>();
+
+    public ClassLinkMetaData(ClassMetaData classMetaData) {
+        this.className = classMetaData.getClassName();
+        this.simpleName = classMetaData.getSimpleName();
+        this.style = classMetaData.isGroovy() ? LinkMetaData.Style.Groovydoc : LinkMetaData.Style.Javadoc;
+        for (MethodMetaData method : classMetaData.getDeclaredMethods()) {
+            addMethod(method, method.getOverrideSignature(), style);
+        }
+    }
+
+    public LinkMetaData getClassLink() {
+        return new LinkMetaData(style, simpleName, null);
+    }
+
+    public LinkMetaData getMethod(String method) {
+        MethodLinkMetaData methodMetaData = findMethod(method);
+        return new LinkMetaData(methodMetaData.style, String.format("%s.%s()", simpleName, methodMetaData.name), methodMetaData.id);
+    }
+
+    private MethodLinkMetaData findMethod(String method) {
+        MethodLinkMetaData metaData = methods.get(method);
+        if (metaData != null) {
+            return metaData;
+        }
+
+        List<MethodLinkMetaData> candidates = new ArrayList<MethodLinkMetaData>();
+        for (MethodLinkMetaData methodLinkMetaData : methods.values()) {
+            if (methodLinkMetaData.name.equals(method)) {
+                candidates.add(methodLinkMetaData);
+            }
+        }
+        if (candidates.isEmpty()) {
+            throw new RuntimeException(String.format("No method '%s' found for class '%s'.", method, className));
+        }
+        if (candidates.size() != 1) {
+            throw new RuntimeException(String.format("Found multiple methods called '%s' in class '%s'. Candidates: %s",
+                    method, className, GUtil.join(candidates, ", ")));
+        }
+        return candidates.get(0);
+    }
+
+    public LinkMetaData.Style getStyle() {
+        return style;
+    }
+
+    public void setStyle(LinkMetaData.Style style) {
+        this.style = style;
+    }
+
+    public void addMethod(MethodMetaData method, String id, LinkMetaData.Style style) {
+        methods.put(method.getOverrideSignature(), new MethodLinkMetaData(method.getName(), method.getOverrideSignature(), id, style));
+    }
+
+    public void attach(ClassMetaDataRepository<ClassLinkMetaData> linkMetaDataClassMetaDataRepository) {
+    }
+
+    private static class MethodLinkMetaData implements Serializable {
+        private final String name;
+        private final String signature;
+        private final String id;
+        private final LinkMetaData.Style style;
+
+        private MethodLinkMetaData(String name, String signature, String id, LinkMetaData.Style style) {
+            this.name = name;
+            this.signature = signature;
+            this.id = id;
+            this.style = style;
+        }
+
+        @Override
+        public String toString() {
+            return signature;
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassMetaData.java
deleted file mode 100644
index 4793210..0000000
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ClassMetaData.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2010 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 org.gradle.build.docs.dsl;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ClassMetaData implements Serializable {
-    private final String superClassName;
-    private final boolean groovy;
-    private final Map<String, PropertyMetaData> classProperties = new HashMap<String, PropertyMetaData>();
-
-    public ClassMetaData(String superClassName, boolean isGroovy) {
-        this.superClassName = superClassName;
-        groovy = isGroovy;
-    }
-
-    public Map<String, PropertyMetaData> getClassProperties() {
-        return classProperties;
-    }
-
-    public boolean isGroovy() {
-        return groovy;
-    }
-
-    public String getSuperClassName() {
-        return superClassName;
-    }
-
-    public void addReadableProperty(String name, String type) {
-        PropertyMetaData property = getProperty(name);
-        property.setType(type);
-    }
-
-    public void addWriteableProperty(String name, String type) {
-        PropertyMetaData property = getProperty(name);
-        property.setWriteable(true);
-    }
-
-    private PropertyMetaData getProperty(String name) {
-        PropertyMetaData property = classProperties.get(name);
-        if (property == null) {
-            property = new PropertyMetaData();
-            classProperties.put(name, property);
-        }
-        return property;
-    }
-}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/DslModel.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/DslModel.groovy
deleted file mode 100644
index 137edad..0000000
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/DslModel.groovy
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.gradle.build.docs.dsl
-
-import org.w3c.dom.Document
-import org.gradle.build.docs.XIncludeAwareXmlProvider
-
-class DslModel {
-    private final File classDocbookDir
-    private final Document document
-    private final Iterable<File> classpath
-    private final Map<String, ClassDoc> classes = [:]
-    private final Map<String, ClassMetaData> classMetaData
-    private final Map<String, ExtensionMetaData> extensionMetaData
-
-    DslModel(File classDocbookDir, Document document, Iterable<File> classpath, Map<String, ClassMetaData> classMetaData, Map<String, ExtensionMetaData> extensionMetaData) {
-        this.classDocbookDir = classDocbookDir
-        this.document = document
-        this.classpath = classpath
-        this.classMetaData = classMetaData
-        this.extensionMetaData = extensionMetaData
-    }
-
-    def getClassDoc(String className) {
-        ClassDoc classDoc = classes[className]
-        if (classDoc == null) {
-            ClassMetaData classMetaData = classMetaData[className]
-            if (!classMetaData) {
-                classMetaData = new ClassMetaData(null, false)
-            }
-            ExtensionMetaData extensionMetaData = extensionMetaData[className]
-            if (!extensionMetaData) {
-                extensionMetaData = new ExtensionMetaData(className)
-            }
-            File classFile = new File(classDocbookDir, "${className}.xml")
-            if (!classFile.isFile()) {
-                throw new RuntimeException("Docbook source file not found for class '$className' in $classDocbookDir.")
-            }
-            XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
-            classDoc = new ClassDoc(className, provider.parse(classFile), classMetaData, extensionMetaData, this)
-            classes[className] = classDoc
-        }
-        return classDoc
-    }
-}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtensionMetaData.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtensionMetaData.groovy
deleted file mode 100644
index 0800088..0000000
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtensionMetaData.groovy
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.gradle.build.docs.dsl
-
-class ExtensionMetaData {
-    final String targetClass
-    final Set<Map<String, String>> extensionClasses = new HashSet()
-
-    ExtensionMetaData(String targetClass) {
-        this.targetClass = targetClass
-    }
-    
-    def void add(String plugin, String extensionClass) {
-        extensionClasses << [plugin: plugin, extensionClass: extensionClass]
-    }
-}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTask.groovy
index 0f28757..03f8c43 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTask.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTask.groovy
@@ -1,18 +1,45 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl
 
-import org.codehaus.groovy.groovydoc.GroovyFieldDoc
-import org.codehaus.groovy.groovydoc.GroovyMethodDoc
-import org.codehaus.groovy.groovydoc.GroovyRootDoc
-import org.codehaus.groovy.tools.groovydoc.GroovyDocTool
-import org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc
-import org.gradle.api.file.FileVisitDetails
+import groovyjarjarantlr.collections.AST
+import org.codehaus.groovy.antlr.AntlrASTProcessor
+import org.codehaus.groovy.antlr.SourceBuffer
+import org.codehaus.groovy.antlr.UnicodeEscapingReader
+import org.codehaus.groovy.antlr.java.Java2GroovyConverter
+import org.codehaus.groovy.antlr.java.JavaLexer
+import org.codehaus.groovy.antlr.java.JavaRecognizer
+import org.codehaus.groovy.antlr.parser.GroovyLexer
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer
+import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal
+import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal
+import org.codehaus.groovy.antlr.treewalker.Visitor
+import org.gradle.api.Action
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.SourceTask
 import org.gradle.api.tasks.TaskAction
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.dsl.model.TypeMetaData
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import org.gradle.build.docs.model.SimpleClassMetaDataRepository
+import org.gradle.util.Clock
 
 /**
  * Extracts meta-data from the Groovy and Java source files which make up the Gradle DSL. Persists the meta-data to a file
- * for later use in generating the docbook source for the DSL.
+ * for later use in generating the docbook source for the DSL, such as by {@link org.gradle.build.docs.dsl.docbook.AssembleDslDocTask}.
  */
 class ExtractDslMetaDataTask extends SourceTask {
     @OutputFile
@@ -20,50 +47,93 @@ class ExtractDslMetaDataTask extends SourceTask {
 
     @TaskAction
     def extract() {
-        project.delete(temporaryDir)
-        project.copy { from source; into temporaryDir }
-        GroovyDocTool groovyDoc = new GroovyDocTool([temporaryDir.absolutePath] as String[])
-        List<String> files = []
-        project.fileTree(temporaryDir).visit { FileVisitDetails fvd ->
-            if (!fvd.isDirectory()) {
-                files << fvd.path
-            }
+        Clock clock = new Clock()
+
+        SimpleClassMetaDataRepository<ClassMetaData> repository = new SimpleClassMetaDataRepository<ClassMetaData>()
+        int counter = 0
+        source.each { File f ->
+            parse(f, repository)
+            counter++
+        }
+
+        TypeNameResolver resolver = new TypeNameResolver(repository)
+        repository.each { name, metaData ->
+            resolve(metaData, resolver)
         }
-        groovyDoc.add(files)
+        repository.store(destFile)
 
-        Map<String, ClassMetaData> allClasses = [:]
-        GroovyRootDoc rootDoc = groovyDoc.rootDoc
-        rootDoc.classes().each { SimpleGroovyClassDoc doc ->
-            String className = doc.qualifiedTypeName()
-            String superClassName = doc.superclass()?.qualifiedTypeName()
-            ClassMetaData classMetaData = new ClassMetaData(superClassName, doc.isGroovy())
-            allClasses[className] = classMetaData
+        println "Parsed $counter classes in ${clock.time}"
+    }
 
-            doc.methods().each { GroovyMethodDoc method ->
-                if (method.name().matches("get.+")) {
-                    String propName = method.name()[3].toLowerCase() + method.name().substring(4)
-                    classMetaData.addReadableProperty(propName, method.returnType().qualifiedTypeName())
-                } else if (method.name().matches("set.+")) {
-                    String propName = method.name()[3].toLowerCase() + method.name().substring(4)
-                    classMetaData.addWriteableProperty(propName, method.returnType().qualifiedTypeName())
+    def parse(File sourceFile, ClassMetaDataRepository<ClassMetaData> repository) {
+        try {
+            sourceFile.withReader { reader ->
+                if (sourceFile.name.endsWith('.java')) {
+                    parseJava(sourceFile, reader, repository)
+                } else {
+                    parseGroovy(sourceFile, reader, repository)
                 }
             }
+        } catch (Exception e) {
+            throw new RuntimeException("Could not parse '$sourceFile'.", e)
+        }
+    }
 
-            // This bit of ugliness is to get Groovydoc to resolve the type names for properties by pretending that
-            // they are fields
-            doc.fields.clear()
-            doc.fields.addAll(doc.properties())
-            doc.methods.clear()
-            doc.resolve(rootDoc)
+    def parseJava(File sourceFile, Reader input, ClassMetaDataRepository<ClassMetaData> repository) {
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(input, sourceBuffer);
+        JavaLexer lexer = new JavaLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        JavaRecognizer parser = JavaRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+        String[] tokenNames = parser.getTokenNames();
 
-            doc.properties().each { GroovyFieldDoc field ->
-                classMetaData.addReadableProperty(field.name(), field.type().qualifiedTypeName())
-                classMetaData.addWriteableProperty(field.name(), field.type().qualifiedTypeName())
-            }
-        }
+        parser.compilationUnit();
+        AST ast = parser.getAST();
 
-        destFile.withObjectOutputStream { ObjectOutputStream outstr ->
-            outstr.writeObject(allClasses)
+        // modify the Java AST into a Groovy AST (just token types)
+        Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames);
+        AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter);
+        java2groovyTraverser.process(ast);
+
+        def visitor = new SourceMetaDataVisitor(sourceBuffer, repository, false)
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+        traverser.process(ast);
+        visitor.complete()
+    }
+
+    def parseGroovy(File sourceFile, Reader input, ClassMetaDataRepository<ClassMetaData> repository) {
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(input, sourceBuffer);
+        GroovyLexer lexer = new GroovyLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        GroovyRecognizer parser = GroovyRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+
+        def visitor = new SourceMetaDataVisitor(sourceBuffer, repository, true)
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+        traverser.process(ast);
+        visitor.complete()
+    }
+
+    def resolve(ClassMetaData classMetaData, TypeNameResolver resolver) {
+        try {
+            if (classMetaData.superClassName) {
+                classMetaData.superClassName = resolver.resolve(classMetaData.superClassName, classMetaData)
+            }
+            for (int i = 0; i < classMetaData.interfaceNames.size(); i++) {
+                classMetaData.interfaceNames[i] = resolver.resolve(classMetaData.interfaceNames[i], classMetaData)
+            }
+            classMetaData.visitTypes(new Action<TypeMetaData>() {
+                void execute(TypeMetaData t) {
+                    resolver.resolve(t, classMetaData)
+                }
+            })
+        } catch (Exception e) {
+            throw new RuntimeException("Could not resolve types in class '$classMetaData.className'.", e)
         }
     }
-}
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/LinkMetaData.java
similarity index 55%
copy from buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/LinkMetaData.java
index a1681cf..38a2a7e 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/LinkMetaData.java
@@ -17,23 +17,28 @@ package org.gradle.build.docs.dsl;
 
 import java.io.Serializable;
 
-public class PropertyMetaData implements Serializable {
-    private String type;
-    private boolean writeable;
+public class LinkMetaData implements Serializable {
+    enum Style { Javadoc, Groovydoc, Dsldoc }
 
-    public String getType() {
-        return type;
+    private final Style style;
+    private final String displayName;
+    private final String urlFragment;
+
+    public LinkMetaData(Style style, String displayName, String urlFragment) {
+        this.style = style;
+        this.displayName = displayName;
+        this.urlFragment = urlFragment;
     }
 
-    public void setType(String type) {
-        this.type = type;
+    public Style getStyle() {
+        return style;
     }
 
-    public boolean isWriteable() {
-        return writeable;
+    public String getDisplayName() {
+        return displayName;
     }
 
-    public void setWriteable(boolean writeable) {
-        this.writeable = writeable;
+    public String getUrlFragment() {
+        return urlFragment;
     }
 }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/SourceMetaDataVisitor.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/SourceMetaDataVisitor.java
new file mode 100644
index 0000000..7e4ee6a
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/SourceMetaDataVisitor.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl;
+
+import groovyjarjarantlr.collections.AST;
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.LineColumn;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+import org.gradle.build.docs.dsl.model.ClassMetaData;
+import org.gradle.build.docs.dsl.model.MethodMetaData;
+import org.gradle.build.docs.dsl.model.TypeMetaData;
+import org.gradle.build.docs.model.ClassMetaDataRepository;
+
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.*;
+
+public class SourceMetaDataVisitor extends VisitorAdapter {
+    private static final Pattern PREV_JAVADOC_COMMENT_PATTERN = Pattern.compile("(?s)/\\*\\*(.*?)\\*/");
+    private static final Pattern GETTER_METHOD_NAME = Pattern.compile("(get|is)(.+)");
+    private static final Pattern SETTER_METHOD_NAME = Pattern.compile("set(.+)");
+    private final SourceBuffer sourceBuffer;
+    private final LinkedList<GroovySourceAST> parseStack = new LinkedList<GroovySourceAST>();
+    private final List<String> imports = new ArrayList<String>();
+    private final ClassMetaDataRepository<ClassMetaData> repository;
+    private final List<ClassMetaData> allClasses = new ArrayList<ClassMetaData>();
+    private final LinkedList<ClassMetaData> classStack = new LinkedList<ClassMetaData>();
+    private final Map<GroovySourceAST, ClassMetaData> typeTokens = new HashMap<GroovySourceAST, ClassMetaData>();
+    private final boolean groovy;
+    private String packageName;
+    private LineColumn lastLineCol;
+
+    SourceMetaDataVisitor(SourceBuffer sourceBuffer, ClassMetaDataRepository<ClassMetaData> repository,
+                          boolean isGroovy) {
+        this.sourceBuffer = sourceBuffer;
+        this.repository = repository;
+        groovy = isGroovy;
+        lastLineCol = new LineColumn(1, 1);
+    }
+
+    public void complete() {
+        for (String anImport : imports) {
+            for (ClassMetaData classMetaData : allClasses) {
+                classMetaData.addImport(anImport);
+            }
+        }
+    }
+
+    @Override
+    public void visitPackageDef(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            packageName = extractName(t);
+        }
+    }
+
+    @Override
+    public void visitImport(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            imports.add(extractName(t));
+        }
+    }
+
+    @Override
+    public void visitClassDef(GroovySourceAST t, int visit) {
+        visitTypeDef(t, visit, false);
+    }
+
+    @Override
+    public void visitInterfaceDef(GroovySourceAST t, int visit) {
+        visitTypeDef(t, visit, true);
+    }
+
+    @Override
+    public void visitEnumDef(GroovySourceAST t, int visit) {
+        visitTypeDef(t, visit, false);
+    }
+
+    @Override
+    public void visitAnnotationDef(GroovySourceAST t, int visit) {
+        visitTypeDef(t, visit, false);
+    }
+
+    private void visitTypeDef(GroovySourceAST t, int visit, boolean isInterface) {
+        if (visit == OPENING_VISIT) {
+            ClassMetaData outerClass = getCurrentClass();
+            String baseName = extractIdent(t);
+            String className = outerClass != null ? outerClass.getClassName() + '.' + baseName
+                    : packageName + '.' + baseName;
+            String comment = getJavaDocCommentsBeforeNode(t);
+            ClassMetaData currentClass = new ClassMetaData(className, packageName, isInterface, groovy, comment);
+            if (outerClass != null) {
+                outerClass.addInnerClassName(className);
+                currentClass.setOuterClassName(outerClass.getClassName());
+            }
+            classStack.addFirst(currentClass);
+            allClasses.add(currentClass);
+            typeTokens.put(t, currentClass);
+            repository.put(className, currentClass);
+        }
+    }
+
+    private ClassMetaData getCurrentClass() {
+        return classStack.isEmpty() ? null : classStack.getFirst();
+    }
+
+    @Override
+    public void visitExtendsClause(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            ClassMetaData currentClass = getCurrentClass();
+            for (
+                    GroovySourceAST child = (GroovySourceAST) t.getFirstChild(); child != null;
+                    child = (GroovySourceAST) child.getNextSibling()) {
+                if (!currentClass.isInterface()) {
+                    currentClass.setSuperClassName(extractName(child));
+                } else {
+                    currentClass.addInterfaceName(extractName(child));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitImplementsClause(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            ClassMetaData currentClass = getCurrentClass();
+            for (
+                    GroovySourceAST child = (GroovySourceAST) t.getFirstChild(); child != null;
+                    child = (GroovySourceAST) child.getNextSibling()) {
+                currentClass.addInterfaceName(extractName(child));
+            }
+        }
+    }
+
+    @Override
+    public void visitMethodDef(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            maybeAddMethod(t);
+            skipJavaDocComment(t);
+        }
+    }
+
+    private void maybeAddMethod(GroovySourceAST t) {
+        String name = extractName(t);
+        if (!groovy && name.equals(getCurrentClass().getSimpleName())) {
+            // A constructor. The java grammar treats a constructor as a method, the groovy grammar does not.
+            return;
+        }
+
+        ASTIterator children = new ASTIterator(t);
+        if (groovy) {
+            children.skip(TYPE_PARAMETERS);
+            children.skip(MODIFIERS);
+        } else {
+            children.skip(MODIFIERS);
+            children.skip(TYPE_PARAMETERS);
+        }
+
+        String rawCommentText = getJavaDocCommentsBeforeNode(t);
+        TypeMetaData returnType = extractTypeName(children.current);
+        MethodMetaData method = getCurrentClass().addMethod(name, returnType, rawCommentText);
+
+        extractParameters(t, method);
+
+        Matcher matcher = GETTER_METHOD_NAME.matcher(name);
+        if (matcher.matches()) {
+            int startName = matcher.start(2);
+            String propName = name.substring(startName, startName + 1).toLowerCase() + name.substring(startName + 1);
+            getCurrentClass().addReadableProperty(propName, returnType, rawCommentText, method);
+            return;
+        }
+
+        if (method.getParameters().size() != 1) {
+            return;
+        }
+        matcher = SETTER_METHOD_NAME.matcher(name);
+        if (matcher.matches()) {
+            int startName = matcher.start(1);
+            String propName = name.substring(startName, startName + 1).toLowerCase() + name.substring(startName + 1);
+            TypeMetaData type = method.getParameters().get(0).getType();
+            getCurrentClass().addWriteableProperty(propName, type, rawCommentText, method);
+        }
+    }
+
+    private void extractParameters(GroovySourceAST t, MethodMetaData method) {
+        GroovySourceAST paramsAst = t.childOfType(PARAMETERS);
+        for (
+                GroovySourceAST child = (GroovySourceAST) paramsAst.getFirstChild(); child != null;
+                child = (GroovySourceAST) child.getNextSibling()) {
+            assert child.getType() == PARAMETER_DEF || child.getType() == VARIABLE_PARAMETER_DEF;
+            TypeMetaData type = extractTypeName((GroovySourceAST) child.getFirstChild().getNextSibling());
+            if (child.getType() == VARIABLE_PARAMETER_DEF) {
+                type.setVarargs();
+            }
+            method.addParameter(extractIdent(child), type);
+        }
+    }
+
+    @Override
+    public void visitVariableDef(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            maybeAddPropertyFromField(t);
+            skipJavaDocComment(t);
+        }
+    }
+
+    private void maybeAddPropertyFromField(GroovySourceAST t) {
+        GroovySourceAST parentNode = getParentNode();
+        boolean isField = parentNode != null && parentNode.getType() == OBJBLOCK;
+        if (!isField) {
+            return;
+        }
+
+        int modifiers = extractModifiers(t);
+        boolean isConst = getCurrentClass().isInterface() || (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));
+        if (isConst) {
+            visitConst(t);
+            return;
+        }
+
+        boolean isProp = groovy && !Modifier.isStatic(modifiers) && !Modifier.isPublic(modifiers)
+                && !Modifier.isProtected(modifiers) && !Modifier.isPrivate(modifiers);
+        if (!isProp) {
+            return;
+        }
+
+        ASTIterator children = new ASTIterator(t);
+        children.skip(MODIFIERS);
+
+        String propertyName = extractIdent(t);
+        TypeMetaData propertyType = extractTypeName(children.current);
+        ClassMetaData currentClass = getCurrentClass();
+
+        MethodMetaData getterMethod = currentClass.addMethod(String.format("get%s", StringUtils.capitalize(
+                propertyName)), propertyType, "");
+        currentClass.addReadableProperty(propertyName, propertyType, getJavaDocCommentsBeforeNode(t), getterMethod);
+        if (!Modifier.isFinal(modifiers)) {
+            MethodMetaData setterMethod = currentClass.addMethod(String.format("set%s", StringUtils.capitalize(
+                    propertyName)), TypeMetaData.VOID, "");
+            setterMethod.addParameter(propertyName, propertyType);
+            currentClass.addWriteableProperty(propertyName, propertyType, getJavaDocCommentsBeforeNode(t), setterMethod);
+        }
+    }
+
+    private void visitConst(GroovySourceAST t) {
+        String constName = extractIdent(t);
+        GroovySourceAST assign = t.childOfType(ASSIGN);
+        String value = null;
+        if (assign != null) {
+            value = extractLiteral(assign.getFirstChild());
+        }
+        getCurrentClass().getConstants().put(constName, value);
+    }
+
+    private String extractLiteral(AST ast) {
+        switch (ast.getType()) {
+            case EXPR:
+                // The java grammar wraps initialisers in an EXPR token
+                return extractLiteral(ast.getFirstChild());
+            case NUM_INT:
+            case NUM_LONG:
+            case NUM_FLOAT:
+            case NUM_DOUBLE:
+            case NUM_BIG_INT:
+            case NUM_BIG_DECIMAL:
+            case STRING_LITERAL:
+                return ast.getText();
+        }
+        return null;
+    }
+
+    public GroovySourceAST pop() {
+        if (!parseStack.isEmpty()) {
+            GroovySourceAST ast = parseStack.removeFirst();
+            ClassMetaData classMetaData = typeTokens.remove(ast);
+            if (classMetaData != null) {
+                assert classMetaData == classStack.getFirst();
+                classStack.removeFirst();
+            }
+            return ast;
+        }
+        return null;
+    }
+
+    @Override
+    public void push(GroovySourceAST t) {
+        parseStack.addFirst(t);
+    }
+
+    private GroovySourceAST getParentNode() {
+        if (parseStack.size() > 1) {
+            return parseStack.get(1);
+        }
+        return null;
+    }
+
+    private int extractModifiers(GroovySourceAST ast) {
+        GroovySourceAST modifiers = ast.childOfType(MODIFIERS);
+        if (modifiers == null) {
+            return 0;
+        }
+        int modifierFlags = 0;
+        for (
+                GroovySourceAST child = (GroovySourceAST) modifiers.getFirstChild(); child != null;
+                child = (GroovySourceAST) child.getNextSibling()) {
+            switch (child.getType()) {
+                case LITERAL_private:
+                    modifierFlags |= Modifier.PRIVATE;
+                    break;
+                case LITERAL_protected:
+                    modifierFlags |= Modifier.PROTECTED;
+                    break;
+                case LITERAL_public:
+                    modifierFlags |= Modifier.PUBLIC;
+                    break;
+                case FINAL:
+                    modifierFlags |= Modifier.FINAL;
+                    break;
+                case LITERAL_static:
+                    modifierFlags |= Modifier.STATIC;
+                    break;
+            }
+        }
+        return modifierFlags;
+    }
+
+    private TypeMetaData extractTypeName(GroovySourceAST ast) {
+        TypeMetaData type = new TypeMetaData();
+        switch (ast.getType()) {
+            case TYPE:
+                GroovySourceAST typeName = (GroovySourceAST) ast.getFirstChild();
+                extractTypeName(typeName, type);
+                break;
+            case WILDCARD_TYPE:
+                // In the groovy grammar, the bounds are sibling of the ?, in the java grammar, they are the child
+                GroovySourceAST bounds = (GroovySourceAST) (groovy ? ast.getNextSibling() : ast.getFirstChild());
+                if (bounds == null) {
+                    type.setWildcard();
+                } else if (bounds.getType() == TYPE_UPPER_BOUNDS) {
+                    type.setUpperBounds(extractTypeName((GroovySourceAST) bounds.getFirstChild()));
+                } else if (bounds.getType() == TYPE_LOWER_BOUNDS) {
+                    type.setLowerBounds(extractTypeName((GroovySourceAST) bounds.getFirstChild()));
+                }
+                break;
+            case IDENT:
+            case DOT:
+                extractTypeName(ast, type);
+                break;
+            default:
+                throw new RuntimeException(String.format("Unexpected token in type name: %s", ast));
+        }
+
+        return type;
+    }
+
+    private void extractTypeName(GroovySourceAST ast, TypeMetaData type) {
+        if (ast == null) {
+            type.setName("java.lang.Object");
+            return;
+        }
+        switch (ast.getType()) {
+            case LITERAL_boolean:
+                type.setName("boolean");
+                return;
+            case LITERAL_byte:
+                type.setName("byte");
+                return;
+            case LITERAL_char:
+                type.setName("char");
+                return;
+            case LITERAL_double:
+                type.setName("double");
+                return;
+            case LITERAL_float:
+                type.setName("float");
+                return;
+            case LITERAL_int:
+                type.setName("int");
+                return;
+            case LITERAL_long:
+                type.setName("long");
+                return;
+            case LITERAL_void:
+                type.setName("void");
+                return;
+            case ARRAY_DECLARATOR:
+                extractTypeName((GroovySourceAST) ast.getFirstChild(), type);
+                type.addArrayDimension();
+                return;
+        }
+
+        type.setName(extractName(ast));
+        GroovySourceAST typeArgs = ast.childOfType(TYPE_ARGUMENTS);
+        if (typeArgs != null) {
+            for (
+                    GroovySourceAST child = (GroovySourceAST) typeArgs.getFirstChild(); child != null;
+                    child = (GroovySourceAST) child.getNextSibling()) {
+                assert child.getType() == TYPE_ARGUMENT;
+                type.addTypeArg(extractTypeName((GroovySourceAST) child.getFirstChild()));
+            }
+        }
+    }
+
+    private void skipJavaDocComment(GroovySourceAST t) {
+        lastLineCol = new LineColumn(t.getLine(), t.getColumn());
+    }
+
+    private String getJavaDocCommentsBeforeNode(GroovySourceAST t) {
+        String result = "";
+        LineColumn thisLineCol = new LineColumn(t.getLine(), t.getColumn());
+        String text = sourceBuffer.getSnippet(lastLineCol, thisLineCol);
+        if (text != null) {
+            Matcher m = PREV_JAVADOC_COMMENT_PATTERN.matcher(text);
+            if (m.find()) {
+                result = m.group(1);
+            }
+        }
+        lastLineCol = thisLineCol;
+        return result;
+    }
+
+    private String extractIdent(GroovySourceAST t) {
+        return t.childOfType(IDENT).getText();
+    }
+
+    private String extractName(GroovySourceAST t) {
+        if (t.getType() == DOT) {
+            GroovySourceAST firstChild = (GroovySourceAST) t.getFirstChild();
+            GroovySourceAST secondChild = (GroovySourceAST) firstChild.getNextSibling();
+            return extractName(firstChild) + "." + extractName(secondChild);
+        }
+        if (t.getType() == IDENT) {
+            return t.getText();
+        }
+        if (t.getType() == STAR) {
+            return t.getText();
+        }
+
+        GroovySourceAST child = t.childOfType(DOT);
+        if (child != null) {
+            return extractName(child);
+        }
+        child = t.childOfType(IDENT);
+        if (child != null) {
+            return extractName(child);
+        }
+
+        throw new RuntimeException(String.format("Unexpected token in name: %s", t));
+    }
+
+    private static class ASTIterator {
+        GroovySourceAST current;
+
+        private ASTIterator(GroovySourceAST parent) {
+            this.current = (GroovySourceAST) parent.getFirstChild();
+        }
+
+        void skip(int token) {
+            if (current != null && current.getType() == token) {
+                current = (GroovySourceAST) current.getNextSibling();
+            }
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/TypeNameResolver.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/TypeNameResolver.java
new file mode 100644
index 0000000..1afb245
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/TypeNameResolver.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl;
+
+import org.apache.commons.lang.StringUtils;
+import org.gradle.api.Action;
+import org.gradle.build.docs.dsl.model.ClassMetaData;
+import org.gradle.build.docs.dsl.model.TypeMetaData;
+import org.gradle.build.docs.model.ClassMetaDataRepository;
+import org.gradle.util.UncheckedException;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Resolves partial type names into fully qualified type names.
+ */
+public class TypeNameResolver {
+    private final Set<String> primitiveTypes = new HashSet<String>();
+    private final List<String> groovyImplicitImportPackages = new ArrayList<String>();
+    private final List<String> groovyImplicitTypes = new ArrayList<String>();
+    private final ClassMetaDataRepository<ClassMetaData> metaDataRepository;
+
+    public TypeNameResolver(ClassMetaDataRepository<ClassMetaData> metaDataRepository) {
+        this.metaDataRepository = metaDataRepository;
+        primitiveTypes.add("boolean");
+        primitiveTypes.add("byte");
+        primitiveTypes.add("char");
+        primitiveTypes.add("short");
+        primitiveTypes.add("int");
+        primitiveTypes.add("long");
+        primitiveTypes.add("float");
+        primitiveTypes.add("double");
+        primitiveTypes.add("void");
+        groovyImplicitImportPackages.add("java.util.");
+        groovyImplicitImportPackages.add("java.io.");
+        groovyImplicitImportPackages.add("java.net.");
+        groovyImplicitImportPackages.add("groovy.lang.");
+        groovyImplicitImportPackages.add("groovy.util.");
+        groovyImplicitTypes.add("java.math.BigDecimal");
+        groovyImplicitTypes.add("java.math.BigInteger");
+
+        // check that groovy is visible.
+        try {
+            getClass().getClassLoader().loadClass("groovy.lang.Closure");
+        } catch (ClassNotFoundException e) {
+            throw UncheckedException.asUncheckedException(e);
+        }
+    }
+
+    /**
+     * Resolves the names in the given type into fully qualified names.
+     */
+    public void resolve(final TypeMetaData type, final ClassMetaData classMetaData) {
+        type.visitTypes(new Action<TypeMetaData>() {
+            public void execute(TypeMetaData t) {
+                t.setName(resolve(t.getName(), classMetaData));
+            }
+        });
+    }
+
+    /**
+     * Resolves a source type name into a fully qualified type name.
+     */
+    public String resolve(String name, ClassMetaData classMetaData) {
+        if (primitiveTypes.contains(name)) {
+            return name;
+        }
+
+        String candidateClassName;
+        String[] innerNames = name.split("\\.");
+        ClassMetaData pos = classMetaData;
+        for (int i = 0; i < innerNames.length; i++) {
+            String innerName = innerNames[i];
+            candidateClassName = pos.getClassName() + '.' + innerName;
+            if (!pos.getInnerClassNames().contains(candidateClassName)) {
+                break;
+            }
+            if (i == innerNames.length - 1) {
+                return candidateClassName;
+            }
+            pos = metaDataRepository.get(candidateClassName);
+        }
+
+        String outerClassName = classMetaData.getOuterClassName();
+        while (outerClassName != null) {
+            if (name.equals(StringUtils.substringAfterLast(outerClassName, "."))) {
+                return outerClassName;
+            }
+            ClassMetaData outerClass = metaDataRepository.get(outerClassName);
+            candidateClassName = outerClassName + '.' + name;
+            if (outerClass.getInnerClassNames().contains(candidateClassName)) {
+                return candidateClassName;
+            }
+            outerClassName = outerClass.getOuterClassName();
+        }
+
+        if (name.contains(".")) {
+            return name;
+        }
+
+        for (String importedClass : classMetaData.getImports()) {
+            String baseName = StringUtils.substringAfterLast(importedClass, ".");
+            if (baseName.equals("*")) {
+                candidateClassName = StringUtils.substringBeforeLast(importedClass, ".") + "." + name;
+                if (metaDataRepository.find(candidateClassName) != null) {
+                    return candidateClassName;
+                }
+                if (importedClass.startsWith("java.") && isVisibleClass(candidateClassName)) {
+                    return candidateClassName;
+                }
+            } else if (name.equals(baseName)) {
+                return importedClass;
+            }
+        }
+
+        candidateClassName = classMetaData.getPackageName() + "." + name;
+        if (metaDataRepository.find(candidateClassName) != null) {
+            return candidateClassName;
+        }
+
+        candidateClassName = "java.lang." + name;
+        if (isVisibleClass(candidateClassName)) {
+            return candidateClassName;
+        }
+
+        if (classMetaData.isGroovy()) {
+            candidateClassName = "java.math." + name;
+            if (groovyImplicitTypes.contains(candidateClassName)) {
+                return candidateClassName;
+            }
+            for (String prefix : groovyImplicitImportPackages) {
+                candidateClassName = prefix + name;
+                if (isVisibleClass(candidateClassName)) {
+                    return candidateClassName;
+                }
+            }
+        }
+
+        return name;
+    }
+
+    private boolean isVisibleClass(String candidateClassName) {
+        try {
+            getClass().getClassLoader().loadClass(candidateClassName);
+            return true;
+        } catch (ClassNotFoundException e) {
+            // Ignore
+        }
+        return false;
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/AssembleDslDocTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/AssembleDslDocTask.groovy
new file mode 100644
index 0000000..b8aa980
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/AssembleDslDocTask.groovy
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.InputFile
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.file.FileCollection
+import org.gradle.api.tasks.InputFiles
+import org.w3c.dom.Document
+import groovy.xml.dom.DOMCategory
+import org.w3c.dom.Element
+import org.gradle.api.tasks.InputDirectory
+import org.gradle.build.docs.XIncludeAwareXmlProvider
+import org.gradle.build.docs.BuildableDOMCategory
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import org.gradle.build.docs.model.SimpleClassMetaDataRepository
+import org.gradle.build.docs.dsl.LinkMetaData
+import org.gradle.api.Project
+import org.gradle.build.docs.dsl.ClassLinkMetaData
+
+/**
+ * Generates the docbook source for the DSL reference guide.
+ *
+ * Uses the following as input:
+ * <ul>
+ * <li>Meta-data extracted from the source by {@link org.gradle.build.docs.dsl.ExtractDslMetaDataTask}.</li>
+ * <li>Meta-data about the plugins, in the form of an XML file.</li>
+ * <li>A docbook template file containing the introductory material and a list of classes to document.</li>
+ * <li>A docbook template file for each class, contained in the {@code classDocbookDir} directory.</li>
+ * </ul>
+ *
+ * Produces the following:
+ * <ul>
+ * <li>A docbook book XML file containing the reference.</li>
+ * <li>A meta-data file containing information about where the canonical documentation for each class can be found:
+ * as dsl doc, javadoc or groovydoc.</li>
+ * </ul>
+ */
+class AssembleDslDocTask extends DefaultTask {
+    @InputFile
+    File sourceFile
+    @InputFile
+    File classMetaDataFile
+    @InputFile
+    File pluginsMetaDataFile
+    @InputDirectory
+    File classDocbookDir
+    @OutputFile
+    File destFile
+    @OutputFile
+    File linksFile
+    @InputFiles
+    FileCollection classpath;
+
+    @TaskAction
+    def transform() {
+        XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
+        provider.parse(sourceFile)
+        transformDocument(provider.document)
+        provider.write(destFile)
+    }
+
+    private def transformDocument(Document document) {
+        ClassMetaDataRepository<ClassMetaData> classRepository = new SimpleClassMetaDataRepository<ClassMetaData>()
+        classRepository.load(classMetaDataFile)
+        ClassMetaDataRepository<ClassLinkMetaData> linkRepository = new SimpleClassMetaDataRepository<ClassLinkMetaData>()
+        classRepository.each {name, ClassMetaData metaData ->
+            linkRepository.put(name, new ClassLinkMetaData(metaData))
+        }
+
+        use(DOMCategory) {
+            use(BuildableDOMCategory) {
+                Map<String, ExtensionMetaData> extensions = loadPluginsMetaData()
+                DslDocModel model = new DslDocModel(classDocbookDir, document, classpath, classRepository, extensions)
+                def root = document.documentElement
+                root.section.table.each { Element table ->
+                    mergeContent(table, model, linkRepository)
+                }
+            }
+        }
+
+        linkRepository.store(linksFile)
+    }
+
+    def loadPluginsMetaData() {
+        XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
+        provider.parse(pluginsMetaDataFile)
+        Map<String, ExtensionMetaData> extensions = [:]
+        provider.root.plugin.each { Element plugin ->
+            def pluginId = plugin.'@id'
+            plugin.extends.each { Element e ->
+                def targetClass = e.'@targetClass'
+                def extensionClass = e.'@extensionClass'
+                def extension = extensions[targetClass]
+                if (!extension) {
+                    extension = new ExtensionMetaData(targetClass)
+                    extensions[targetClass] = extension
+                }
+                extension.add(pluginId, extensionClass)
+            }
+        }
+        return extensions
+    }
+
+    def mergeContent(Element typeTable, DslDocModel model, ClassMetaDataRepository<ClassLinkMetaData> linkRepository) {
+        def title = typeTable.title[0].text()
+
+        if (title.matches('(?i).* types')) {
+            mergeTypes(typeTable, model, linkRepository)
+        } else if (title.matches('(?i).* blocks')) {
+            mergeBlocks(typeTable, model)
+        } else {
+            return
+        }
+
+        typeTable['@role'] = 'dslTypes'
+    }
+
+    def mergeBlocks(Element blocksTable, DslDocModel model) {
+        blocksTable.addFirst {
+            thead {
+                tr {
+                    td('Block')
+                    td('Description')
+                }
+            }
+        }
+
+        def project = model.getClassDoc(Project.class.name)
+
+        blocksTable.tr.each { Element tr ->
+            mergeBlock(tr, project)
+        }
+    }
+
+    def mergeBlock(Element tr, ClassDoc project) {
+        String blockName = tr.td[0].text().trim()
+        BlockDoc blockDoc = project.getBlock(blockName)
+        tr.children = {
+            td { link(linkend: blockDoc.id) { literal("$blockName { }")} }
+            td(blockDoc.description)
+        }
+    }
+
+    def mergeTypes(Element typeTable, DslDocModel model, ClassMetaDataRepository<ClassLinkMetaData> linkRepository) {
+        typeTable.addFirst {
+            thead {
+                tr {
+                    td('Type')
+                    td('Description')
+                }
+            }
+        }
+
+        typeTable.tr.each { Element tr ->
+            mergeType(tr, model, linkRepository)
+        }
+    }
+
+    def mergeType(Element tr, DslDocModel model, ClassMetaDataRepository<ClassLinkMetaData> linkRepository) {
+        String className = tr.td[0].text().trim()
+        ClassDoc classDoc = model.getClassDoc(className)
+        try {
+            new ClassDocRenderer(new LinkRenderer(tr.ownerDocument, model)).mergeContent(classDoc)
+            def linkMetaData = linkRepository.get(className)
+            linkMetaData.style = LinkMetaData.Style.Dsldoc
+            classDoc.classMethods.each { methodDoc ->
+                linkMetaData.addMethod(methodDoc.metaData, methodDoc.id, LinkMetaData.Style.Dsldoc)
+            }
+            Element root = tr.ownerDocument.documentElement
+            root << classDoc.classSection
+            tr.children = {
+                td {
+                    link(linkend: classDoc.id) { literal(classDoc.simpleName) }
+                }
+                td(classDoc.description)
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to generate documentation for class '$className'.", e)
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexer.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexer.java
new file mode 100644
index 0000000..cccbb2e
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexer.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * Converts the main description of a javadoc comment into a stream of tokens.
+ */
+class BasicJavadocLexer implements JavadocLexer {
+    private static final Pattern HTML_ELEMENT = Pattern.compile("(?s)<\\\\?.+?>");
+    private static final Pattern ELEMENT_ATTRIBUTE = Pattern.compile("(?s)\\w+(\\s*=\\s*('.*?')|(\".*?\"))?");
+    private static final Pattern END_ATTRIBUTE_NAME = Pattern.compile("=|(\\s)|(/>)|>");
+    private static final Pattern ATTRIBUTE_SEPARATOR = Pattern.compile("\\s*=\\s*");
+    private static final Pattern END_ELEMENT_NAME = Pattern.compile("\\s+|(/>)|>");
+    private static final Pattern END_ELEMENT = Pattern.compile("(/>)|>");
+    private static final Pattern HTML_ENCODED_CHAR = Pattern.compile("&#\\d+;");
+    private static final Pattern HTML_ENTITY = Pattern.compile("&.+?;");
+    private static final Pattern TAG = Pattern.compile("(?s)\\{@.+?\\}");
+    private static final Pattern END_TAG_NAME = Pattern.compile("(?s)\\s|}");
+    private static final Pattern WHITESPACE_WITH_EOL = Pattern.compile("(?s)\\s+");
+    private static final Map<String, String> ENTITIES = new HashMap<String, String>();
+
+    static {
+        ENTITIES.put("amp", "&");
+        ENTITIES.put("lt", "<");
+        ENTITIES.put("gt", ">");
+        ENTITIES.put("quot", "\"");
+        ENTITIES.put("apos", "'");
+    }
+
+    private final JavadocScanner scanner;
+
+    BasicJavadocLexer(JavadocScanner scanner) {
+        this.scanner = scanner;
+    }
+
+    public void pushText(String rawCommentText) {
+        scanner.pushText(rawCommentText);
+    }
+
+    public void visit(TokenVisitor visitor) {
+        while (!scanner.isEmpty()) {
+            if (scanner.lookingAt(HTML_ELEMENT)) {
+                parseStartElement(visitor);
+                continue;
+            }
+            if (scanner.lookingAt(TAG)) {
+                parseJavadocTag(visitor);
+                continue;
+            }
+
+            StringBuilder text = new StringBuilder();
+            while (!scanner.isEmpty()) {
+                if (scanner.lookingAt(HTML_ELEMENT)) {
+                    break;
+                }
+                if (scanner.lookingAt(TAG)) {
+                    break;
+                }
+                if (scanner.lookingAt(HTML_ENCODED_CHAR)) {
+                    parseHtmlEncodedChar(text);
+                } else if (scanner.lookingAt(HTML_ENTITY)) {
+                    parseHtmlEntity(text);
+                } else {
+                    text.append(scanner.getFirst());
+                    scanner.next();
+                }
+            }
+
+            visitor.onText(text.toString());
+        }
+    }
+
+    private void parseHtmlEntity(StringBuilder buffer) {
+        scanner.next();
+        scanner.mark();
+        scanner.find(';');
+        String value = ENTITIES.get(scanner.region().toLowerCase());
+        buffer.append(value);
+        scanner.next();
+    }
+
+    private void parseHtmlEncodedChar(StringBuilder buffer) {
+        scanner.next(2);
+        scanner.mark();
+        scanner.find(';');
+        String value = new String(new char[]{(char) Integer.parseInt(scanner.region())});
+        buffer.append(value);
+        scanner.next();
+    }
+
+    private void parseJavadocTag(TokenVisitor visitor) {
+        // start of tag marker
+        scanner.next(2);
+
+        // tag name
+        scanner.mark();
+        scanner.find(END_TAG_NAME);
+        String tagName = scanner.region();
+        visitor.onStartJavadocTag(tagName);
+        scanner.skip(WHITESPACE_WITH_EOL);
+
+        // value
+        if (!scanner.lookingAt('}')) {
+            scanner.mark();
+            scanner.find('}');
+            String value = scanner.region();
+            visitor.onText(value);
+        }
+
+        // end of tag marker
+        if (scanner.lookingAt('}')) {
+            visitor.onEndJavadocTag(tagName);
+            scanner.next();
+        }
+    }
+
+    private void parseStartElement(TokenVisitor visitor) {
+        // start element marker
+        scanner.next();
+        boolean isEnd = false;
+        if (scanner.lookingAt('/')) {
+            isEnd = true;
+            scanner.next();
+        }
+
+        // element name
+        scanner.skip(WHITESPACE_WITH_EOL);
+        scanner.mark();
+        scanner.find(END_ELEMENT_NAME);
+        String elementName = scanner.region().toLowerCase();
+        if (isEnd) {
+            visitor.onEndHtmlElement(elementName);
+        } else {
+            visitor.onStartHtmlElement(elementName);
+        }
+
+        // attributes
+        scanner.skip(WHITESPACE_WITH_EOL);
+        while (!scanner.isEmpty() && scanner.lookingAt(ELEMENT_ATTRIBUTE)) {
+            // attribute name
+            scanner.mark();
+            scanner.find(END_ATTRIBUTE_NAME);
+            String attrName = scanner.region();
+
+            // separator
+            scanner.skip(ATTRIBUTE_SEPARATOR);
+
+            // value
+            char quote = scanner.getFirst();
+            scanner.next();
+            StringBuilder attrValue = new StringBuilder();
+            while (!scanner.isEmpty() && !scanner.lookingAt(quote)) {
+                if (scanner.lookingAt(HTML_ENCODED_CHAR)) {
+                    parseHtmlEncodedChar(attrValue);
+                } else if (scanner.lookingAt(HTML_ENTITY)) {
+                    parseHtmlEntity(attrValue);
+                } else {
+                    attrValue.append(scanner.getFirst());
+                    scanner.next();
+                }
+            }
+            visitor.onHtmlElementAttribute(attrName, attrValue.toString());
+            scanner.next();
+            scanner.skip(WHITESPACE_WITH_EOL);
+        }
+
+        if (!isEnd) {
+            visitor.onStartHtmlElementComplete(elementName);
+        }
+
+        // end element marker
+        if (scanner.lookingAt('/')) {
+            visitor.onEndHtmlElement(elementName);
+        }
+        scanner.skip(END_ELEMENT);
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BlockDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BlockDoc.groovy
new file mode 100644
index 0000000..4197b17
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/BlockDoc.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.w3c.dom.Element
+import org.gradle.build.docs.dsl.model.TypeMetaData
+
+class BlockDoc {
+    private final MethodDoc blockMethod
+    private final PropertyDoc blockProperty
+    private final TypeMetaData type
+    private boolean multiValued
+
+    BlockDoc(MethodDoc blockMethod, PropertyDoc blockProperty, TypeMetaData type, boolean multiValued) {
+        this.blockMethod = blockMethod
+        this.type = type
+        this.blockProperty = blockProperty
+        this.multiValued = multiValued
+    }
+
+    String getId() {
+        return blockMethod.id
+    }
+
+    String getName() {
+        return blockMethod.name
+    }
+
+    boolean isMultiValued() {
+        return multiValued
+    }
+
+    TypeMetaData getType() {
+        return type
+    }
+
+    Element getDescription() {
+        return blockMethod.description;
+    }
+
+    List<Element> getComment() {
+        return blockMethod.comment
+    }
+    
+    PropertyDoc getBlockProperty() {
+        return blockProperty
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDoc.groovy
new file mode 100644
index 0000000..3f11251
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDoc.groovy
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.dsl.model.PropertyMetaData
+import org.w3c.dom.Document
+import org.w3c.dom.Element
+import org.w3c.dom.Node
+import org.gradle.build.docs.dsl.model.MethodMetaData
+import org.w3c.dom.Text
+
+class ClassDoc {
+    private final String className
+    private final String id
+    private final String simpleName
+    final ClassMetaData classMetaData
+    private final Element classSection
+    private final ExtensionMetaData extensionMetaData
+    private final List<PropertyDoc> classProperties = []
+    private final List<MethodDoc> classMethods = []
+    private final List<BlockDoc> classBlocks = []
+    private final List<ClassExtensionDoc> classExtensions = []
+    private final JavadocConverter javadocConverter
+    private final DslDocModel model
+    private final Element propertiesTable
+    private final Element methodsTable
+    private final Element propertiesSection
+    private final Element methodsSection
+    private List<Element> comment
+    private final GenerationListener listener = new DefaultGenerationListener()
+
+    ClassDoc(String className, Element classContent, Document targetDocument, ClassMetaData classMetaData, ExtensionMetaData extensionMetaData, DslDocModel model, JavadocConverter javadocConverter) {
+        this.className = className
+        id = className
+        simpleName = className.tokenize('.').last()
+        this.classMetaData = classMetaData
+        this.javadocConverter = javadocConverter
+        this.model = model
+        this.extensionMetaData = extensionMetaData
+
+        classSection = targetDocument.createElement('chapter')
+
+        classContent.childNodes.each { Node n ->
+            classSection << n
+        }
+
+        propertiesTable = getTable('Properties')
+        propertiesSection = propertiesTable.parentNode
+        methodsTable = getTable('Methods')
+        methodsSection = methodsTable.parentNode
+    }
+
+    def getId() { return id }
+
+    def getName() { return className }
+
+    def getSimpleName() { return simpleName }
+
+    def getComment() { return comment }
+
+    def getClassProperties() { return classProperties }
+
+    def getClassMethods() { return classMethods }
+
+    def getClassBlocks() { return classBlocks }
+
+    def getClassExtensions() { return classExtensions }
+
+    def getClassSection() { return classSection }
+
+    def getPropertiesTable() { return propertiesTable }
+
+    def getPropertiesSection() { return propertiesSection }
+
+    def getPropertyDetailsSection() { return getSection('Property details') }
+
+    def getMethodsTable() { return methodsTable }
+
+    def getMethodsSection() { return methodsSection }
+
+    def getMethodDetailsSection() { return getSection('Method details') }
+
+    def getBlocksTable() { return getTable('Script blocks') }
+
+    def getBlockDetailsSection() { return getSection('Script block details') }
+
+    ClassDoc mergeContent() {
+        buildDescription()
+        buildProperties()
+        buildMethods()
+        buildExtensions()
+        return this
+    }
+
+    ClassDoc buildDescription() {
+        comment = javadocConverter.parse(classMetaData, listener).docbook
+        return this
+    }
+
+    ClassDoc buildProperties() {
+        List<Element> header = propertiesTable.thead.tr[0].td.collect { it }
+        if (header.size() < 1) {
+            throw new RuntimeException("Expected at least 1 <td> in <thead>/<tr>, found: $header")
+        }
+        Map<String, Element> inheritedValueTitleMapping = [:]
+        List<Element> valueTitles = []
+        header.eachWithIndex { element, index ->
+            if (index == 0) { return }
+            Element override = element.overrides[0]
+            if (override) {
+                element.removeChild(override)
+                inheritedValueTitleMapping.put(override.textContent, element)
+            }
+            if (element.firstChild instanceof Text) {
+                element.firstChild.textContent = element.firstChild.textContent.replaceFirst(/^\s+/, '')
+            }
+            if (element.lastChild instanceof Text) {
+                element.lastChild.textContent = element.lastChild.textContent.replaceFirst(/\s+$/, '')
+            }
+            valueTitles.add(element)
+        }
+
+        ClassDoc superClass = classMetaData.superClassName ? model.getClassDoc(classMetaData.superClassName) : null
+
+        Map<String, PropertyDoc> props = new TreeMap<String, PropertyDoc>()
+        if (superClass) {
+            superClass.getClassProperties().each { propertyDoc ->
+                def additionalValues = new LinkedHashMap<String, ExtraAttributeDoc>()
+                propertyDoc.additionalValues.each { attributeDoc ->
+                    def key = attributeDoc.key
+                    if (inheritedValueTitleMapping[key]) {
+                        ExtraAttributeDoc newAttribute = new ExtraAttributeDoc(inheritedValueTitleMapping[key], attributeDoc.valueCell)
+                        additionalValues.put(newAttribute.key, newAttribute)
+                    } else {
+                        additionalValues.put(key, attributeDoc)
+                    }
+                }
+
+                props[propertyDoc.name] = propertyDoc.forClass(classMetaData, additionalValues.values() as List)
+            }
+        }
+
+        propertiesTable.tr.each { Element tr ->
+            def cells = tr.td.collect { it }
+            if (cells.size() != header.size()) {
+                throw new RuntimeException("Expected ${header.size()} <td> elements in <tr>, found: $tr")
+            }
+            String propName = cells[0].text().trim()
+            PropertyMetaData property = classMetaData.findProperty(propName)
+            if (!property) {
+                throw new RuntimeException("No metadata for property '$className.$propName'. Available properties: ${classMetaData.propertyNames}")
+            }
+
+            def additionalValues = new LinkedHashMap<String, ExtraAttributeDoc>()
+
+            if (superClass) {
+                def overriddenProp = props.get(propName)
+                if (overriddenProp) {
+                    overriddenProp.additionalValues.each { attributeDoc ->
+                        additionalValues.put(attributeDoc.key, attributeDoc)
+                    }
+                }
+            }
+
+            header.eachWithIndex { col, i ->
+                if (i == 0 || !cells[i].firstChild) { return }
+                def attributeDoc = new ExtraAttributeDoc(valueTitles[i-1], cells[i])
+                additionalValues.put(attributeDoc.key, attributeDoc)
+            }
+            PropertyDoc propertyDoc = new PropertyDoc(property, javadocConverter.parse(property, listener).docbook, additionalValues.values() as List)
+            if (propertyDoc.description == null) {
+                throw new RuntimeException("Docbook content for '$className.$propName' does not contain a description paragraph.")
+            }
+
+            props[propName] = propertyDoc
+        }
+
+        classProperties.addAll(props.values())
+
+        return this
+    }
+
+    ClassDoc buildMethods() {
+        Set signatures = [] as Set
+
+        methodsTable.tr.each { Element tr ->
+            def cells = tr.td
+            if (cells.size() != 1) {
+                throw new RuntimeException("Expected 1 cell in <tr>, found: $tr")
+            }
+            String methodName = cells[0].text().trim()
+            Collection<MethodMetaData> methods = classMetaData.declaredMethods.findAll { it.name == methodName }
+            if (!methods) {
+                throw new RuntimeException("No metadata for method '$className.$methodName()'. Available methods: ${classMetaData.declaredMethods.collect {it.name} as TreeSet}")
+            }
+            methods.each { method ->
+                def methodDoc = new MethodDoc(method, javadocConverter.parse(method, listener).docbook)
+                if (!methodDoc.description) {
+                    throw new RuntimeException("Docbook content for '$className $method.signature' does not contain a description paragraph.")
+                }
+                def property = findProperty(method.name)
+                def multiValued = false
+                if (method.parameters.size() == 1 && method.parameters[0].type.signature == Closure.class.name && property) {
+                    def type = property.metaData.type
+                    if (type.name == 'java.util.List' || type.name == 'java.util.Collection' || type.name == 'java.util.Set' || type.name == 'java.util.Iterable') {
+                        type = type.typeArgs[0]
+                        multiValued = true
+                    }
+                    classBlocks << new BlockDoc(methodDoc, property, type, multiValued)
+                } else {
+                    classMethods << methodDoc
+                    signatures << method.overrideSignature
+                }
+            }
+        }
+
+        if (classMetaData.superClassName) {
+            ClassDoc supertype = model.getClassDoc(classMetaData.superClassName)
+            supertype.getClassMethods().each { method ->
+                if (signatures.add(method.metaData.overrideSignature)) {
+                    classMethods << method.forClass(classMetaData)
+                }
+            }
+        }
+
+        classMethods.sort { it.metaData.overrideSignature }
+        classBlocks.sort { it.name }
+
+        return this
+    }
+
+    ClassDoc buildExtensions() {
+        extensionMetaData.extensionClasses.keySet().each { String pluginId ->
+            List<ClassDoc> extensionClasses = []
+            extensionMetaData.extensionClasses.get(pluginId).each { String extensionClass ->
+                extensionClasses << model.getClassDoc(extensionClass)
+            }
+            extensionClasses.sort { it.name }
+            classExtensions << new ClassExtensionDoc(pluginId, extensionClasses)
+        }
+
+        classExtensions.sort { it.pluginId }
+
+        return this
+    }
+
+    String getStyle() {
+        return classMetaData.groovy ? 'groovydoc' : 'javadoc'
+    }
+
+    private Element getTable(String title) {
+        def table = getSection(title).table[0]
+        if (!table) {
+            throw new RuntimeException("Section '$title' does not contain a <table> element.")
+        }
+        if (!table.thead[0]) {
+            throw new RuntimeException("Table '$title' does not contain a <thead> element.")
+        }
+        if (!table.thead[0].tr[0]) {
+            throw new RuntimeException("Table '$title' does not contain a <thead>/<tr> element.")
+        }
+        return table
+    }
+
+    private Element getSection(String title) {
+        def sections = classSection.section.findAll {
+            it.title[0] && it.title[0].text().trim() == title
+        }
+        if (sections.size() < 1) {
+            throw new RuntimeException("Docbook content for $className does not contain a '$title' section.")
+        }
+        return sections[0]
+    }
+
+    Element getHasDescription() {
+        def paras = classSection.para
+        return paras.size() > 0 ? paras[0] : null
+    }
+
+    Element getDescription() {
+        def paras = classSection.para
+        if (paras.size() < 1) {
+            throw new RuntimeException("Docbook content for $className does not contain a description paragraph.")
+        }
+        return paras[0]
+    }
+
+    PropertyDoc findProperty(String name) {
+        return classProperties.find { it.name == name }
+    }
+
+    BlockDoc getBlock(String name) {
+        def block = classBlocks.find { it.name == name }
+        if (block) {
+            return block
+        }
+        for (extensionDoc in classExtensions) {
+            block = extensionDoc.extensionBlocks.find { it.name == name }
+            if (block) {
+                return block
+            }
+        }
+        throw new RuntimeException("Class $className does not have a script block '$name'.")
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRenderer.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRenderer.groovy
new file mode 100644
index 0000000..d8ba60a
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRenderer.groovy
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+class ClassDocRenderer {
+    private final LinkRenderer linkRenderer
+    private final GenerationListener listener = new DefaultGenerationListener()
+
+    ClassDocRenderer(LinkRenderer linkRenderer) {
+        this.linkRenderer = linkRenderer
+    }
+
+    void mergeContent(ClassDoc classDoc) {
+        listener.start("class $classDoc.className")
+        try {
+            mergeDescription(classDoc)
+            mergeProperties(classDoc)
+            mergeMethods(classDoc)
+            mergeBlocks(classDoc)
+            mergeExtensions(classDoc)
+        } finally {
+            listener.finish()
+        }
+    }
+
+    void mergeDescription(ClassDoc classDoc) {
+        def classContent = classDoc.classSection
+        classContent.setAttribute('id', classDoc.id)
+        classContent.addFirst {
+            title(classDoc.simpleName)
+            segmentedlist {
+                segtitle('API Documentation')
+                seglistitem {
+                    seg { apilink('class': classDoc.name, style: classDoc.style) }
+                }
+            }
+            appendChildren classDoc.comment
+        }
+    }
+
+    void mergeProperties(ClassDoc classDoc) {
+        def propertiesTable = classDoc.propertiesTable
+        def propertiesSection = classDoc.propertiesSection
+        def classProperties = classDoc.classProperties
+
+        if (classProperties.isEmpty()) {
+            propertiesSection.children = {
+                title('Properties')
+                para('No properties')
+            }
+            return
+        }
+
+        def propertyTableHeader = propertiesTable.thead[0].tr[0]
+        def cells = propertyTableHeader.td.collect { it }
+        cells = cells.subList(1, cells.size())
+
+        propertiesTable.children = {
+            title("Properties - $classDoc.simpleName")
+            thead {
+                tr { td('Property'); td('Description') }
+            }
+            classProperties.each { propDoc ->
+                tr {
+                    td { link(linkend: propDoc.id) { literal(propDoc.name) } }
+                    td { appendChild(propDoc.description) }
+                }
+            }
+        }
+
+        propertiesSection.addAfter {
+            section {
+                title('Property details')
+                classProperties.each { propDoc ->
+                    section(id: propDoc.id, role: 'detail') {
+                        title {
+                            appendChild linkRenderer.link(propDoc.metaData.type, listener)
+                            text(' ')
+                            literal(propDoc.name)
+                            if (!propDoc.metaData.writeable) {
+                                text(' (read-only)')
+                            }
+                        }
+                        appendChildren propDoc.comment
+                        if (propDoc.additionalValues) {
+                            segmentedlist {
+                                propDoc.additionalValues.each { attributeDoc ->
+                                    segtitle { appendChildren(attributeDoc.title) }
+                                }
+                                seglistitem {
+                                    propDoc.additionalValues.each { ExtraAttributeDoc attributeDoc ->
+                                        seg { appendChildren(attributeDoc.value) }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void mergeMethods(ClassDoc classDoc) {
+        def methodsSection = classDoc.methodsSection
+        def methodsTable = classDoc.methodsTable
+        def classMethods = classDoc.classMethods
+
+        if (classMethods.isEmpty()) {
+            methodsSection.children = {
+                title('Methods')
+                para('No methods')
+            }
+            return
+        }
+
+        methodsTable.children = {
+            title("Methods - $classDoc.simpleName")
+            thead {
+                tr {
+                    td('Method')
+                    td('Description')
+                }
+            }
+            classMethods.each { method ->
+                tr {
+                    td {
+                        literal {
+                            link(linkend: method.id) { text(method.name) }
+                            text('(')
+                            method.metaData.parameters.eachWithIndex { param, index ->
+                                if ( index > 0 ) {
+                                    text(', ')
+                                }
+                                text(param.name)
+                            }
+                            text(')')
+                        }
+                    }
+                    td { appendChild method.description }
+                }
+            }
+        }
+
+        methodsSection.addAfter {
+            section {
+                title('Method details')
+                classMethods.each { method ->
+                    section(id: method.id, role: 'detail') {
+                        title {
+                            appendChild linkRenderer.link(method.metaData.returnType, listener)
+                            text(' ')
+                            literal(method.name)
+                            text('(')
+                            method.metaData.parameters.eachWithIndex {param, i ->
+                                if (i > 0) {
+                                    text(', ')
+                                }
+                                appendChild linkRenderer.link(param.type, listener)
+                                text(" $param.name")
+                            }
+                            text(')')
+                        }
+                        appendChildren method.comment
+                    }
+                }
+            }
+        }
+    }
+
+    void mergeBlocks(ClassDoc classDoc) {
+        def targetSection = classDoc.methodsSection
+        def classBlocks = classDoc.classBlocks
+
+        if (classBlocks.isEmpty()) {
+            targetSection.addBefore {
+                section {
+                    title('Script blocks')
+                    para('No script blocks')
+                }
+            }
+            return
+        }
+
+        targetSection.addBefore {
+            section {
+                title('Script blocks')
+                table {
+                    title("Script blocks - $classDoc.simpleName")
+                    thead {
+                        tr {
+                            td('Block'); td('Description')
+                        }
+                    }
+                    classBlocks.each { block ->
+                        tr {
+                            td { link(linkend: block.id) { literal(block.name) } }
+                            td { appendChild block.description }
+                        }
+                    }
+                }
+            }
+            section {
+                title('Script block details')
+                classBlocks.each { block ->
+                    section(id: block.id, role: 'detail') {
+                        title {
+                            literal(block.name); text(' { }')
+                        }
+                        appendChildren block.comment
+                        segmentedlist {
+                            segtitle('Delegates to')
+                            seglistitem {
+                                seg {
+                                    if (block.multiValued) {
+                                        text('Each ')
+                                        appendChild linkRenderer.link(block.type, listener)
+                                        text(' in ')
+                                        link(linkend: block.blockProperty.id) { literal(block.blockProperty.name) }
+                                    } else {
+                                        appendChild linkRenderer.link(block.type, listener)
+                                        text(' from ')
+                                        link(linkend: block.blockProperty.id) { literal(block.blockProperty.name) }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void mergeExtensions(ClassDoc classDoc) {
+        if (!classDoc.classExtensions) {
+            return
+        }
+        mergeExtensionProperties(classDoc)
+        mergeExtensionMethods(classDoc)
+        mergeExtensionBlocks(classDoc)
+    }
+
+    void mergeExtensionProperties(ClassDoc classDoc) {
+        classDoc.propertiesTable.addAfter {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                if (!extension.extensionProperties) {
+                    return
+                }
+                section {
+                    title { text("Properties added by the "); literal(extension.pluginId); text(" plugin") }
+                    titleabbrev { literal(extension.pluginId); text(" plugin") }
+                    table {
+                        title { text("Properties - "); literal(extension.pluginId); text(" plugin") }
+                        thead { tr { td('Property'); td('Description') } }
+                        extension.extensionProperties.each { propertyDoc ->
+                            tr {
+                                td { link(linkend: propertyDoc.id) { literal(propertyDoc.name) } }
+                                td { appendChild propertyDoc.description }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        classDoc.propertyDetailsSection << {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                extension.extensionProperties.each { propDoc ->
+                    section(id: propDoc.id, role: 'detail') {
+                        title {
+                            appendChild linkRenderer.link(propDoc.metaData.type, listener)
+                            text(' ')
+                            literal(propDoc.name)
+                            if (!propDoc.metaData.writeable) {
+                                text(' (read-only)')
+                            }
+                        }
+                        appendChildren propDoc.comment
+                        if (propDoc.additionalValues) {
+                            segmentedlist {
+                                propDoc.additionalValues.each { attributeDoc ->
+                                    segtitle { appendChildren(attributeDoc.title) }
+                                }
+                                seglistitem {
+                                    propDoc.additionalValues.each { ExtraAttributeDoc attributeDoc ->
+                                        seg { appendChildren(attributeDoc.value) }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    void mergeExtensionMethods(ClassDoc classDoc) {
+        classDoc.methodsTable.addAfter {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                if (!extension.extensionMethods) {
+                    return
+                }
+                section {
+                    title { text("Methods added by the "); literal(extension.pluginId); text(" plugin") }
+                    titleabbrev { literal(extension.pluginId); text(" plugin") }
+                    table {
+                        title { text("Methods - "); literal(extension.pluginId); text(" plugin") }
+                        thead { tr { td('Method'); td('Description') } }
+                        extension.extensionMethods.each { method ->
+                            tr {
+                                td {
+                                    literal {
+                                        link(linkend: method.id) { text(method.name) }
+                                        text('(')
+                                        method.metaData.parameters.eachWithIndex { param, index ->
+                                            if ( index > 0 ) {
+                                                text(', ')
+                                            }
+                                            text(param.name)
+                                        }
+                                        text(')')
+                                    }
+                                }
+                                td { appendChild method.description }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        classDoc.methodDetailsSection << {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                extension.extensionMethods.each { method ->
+                    section(id: method.id, role: 'detail') {
+                        title {
+                            appendChild linkRenderer.link(method.metaData.returnType, listener)
+                            text(' ')
+                            literal(method.name)
+                            text('(')
+                            method.metaData.parameters.eachWithIndex {param, i ->
+                                if (i > 0) {
+                                    text(', ')
+                                }
+                                appendChild linkRenderer.link(param.type, listener)
+                                text(" $param.name")
+                            }
+                            text(')')
+                        }
+                        appendChildren method.comment
+                    }
+                }
+            }
+        }
+    }
+
+    void mergeExtensionBlocks(ClassDoc classDoc) {
+        classDoc.blocksTable.addAfter {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                if (!extension.extensionBlocks) {
+                    return
+                }
+                section {
+                    title { text("Script blocks added by the "); literal(extension.pluginId); text(" plugin") }
+
+                    titleabbrev { literal(extension.pluginId); text(" plugin") }
+                    table {
+                        title { text("Script blocks - "); literal(extension.pluginId); text(" plugin") }
+                        thead { tr { td('Block'); td('Description') } }
+                        extension.extensionBlocks.each { blockDoc ->
+                            tr {
+                                td { link(linkend: blockDoc.id) { literal(blockDoc.name) } }
+                                td { appendChild blockDoc.description }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        classDoc.blockDetailsSection << {
+            classDoc.classExtensions.each { ClassExtensionDoc extension ->
+                extension.extensionBlocks.each { block ->
+                    section(id: block.id, role: 'detail') {
+                        title {
+                            literal(block.name); text(' { }')
+                        }
+                        appendChildren block.comment
+                        segmentedlist {
+                            segtitle('Delegates to')
+                            seglistitem {
+                                seg {
+                                    if (block.multiValued) {
+                                        text('Each ')
+                                        appendChild linkRenderer.link(block.type, listener)
+                                        text(' in ')
+                                        link(linkend: block.blockProperty.id) { literal(block.blockProperty.name) }
+                                    } else {
+                                        appendChild linkRenderer.link(block.type, listener)
+                                        text(' from ')
+                                        link(linkend: block.blockProperty.id) { literal(block.blockProperty.name) }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassExtensionDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassExtensionDoc.groovy
new file mode 100644
index 0000000..59e0dd4
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ClassExtensionDoc.groovy
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+class ClassExtensionDoc {
+    private final List<ClassDoc> extensionClass
+    private final String pluginId
+
+    ClassExtensionDoc(String pluginId, List<ClassDoc> extensionClass) {
+        this.pluginId = pluginId
+        this.extensionClass = extensionClass
+    }
+
+    String getPluginId() {
+        return pluginId
+    }
+
+    List<ClassDoc> getExtensionClasses() {
+        extensionClass
+    }
+
+    List<PropertyDoc> getExtensionProperties() {
+        return extensionClass.inject([]) {list, eClass -> eClass.classProperties.inject(list) {x, prop -> x << prop } }.sort { it.name }
+    }
+
+    List<MethodDoc> getExtensionMethods() {
+        return extensionClass.inject([]) {list, eClass -> eClass.classMethods.inject(list) {x, method -> x << method } }.sort { it.name }
+    }
+
+    List<BlockDoc> getExtensionBlocks() {
+        return extensionClass.inject([]) {list, eClass -> eClass.classBlocks.inject(list) {x, block -> x << block } }.sort { it.name }
+    }
+}
+
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DefaultGenerationListener.java
similarity index 50%
copy from buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DefaultGenerationListener.java
index a1681cf..0e0abe2 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DefaultGenerationListener.java
@@ -13,27 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.build.docs.dsl;
+package org.gradle.build.docs.dsl.docbook;
 
-import java.io.Serializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class PropertyMetaData implements Serializable {
-    private String type;
-    private boolean writeable;
+import java.util.LinkedList;
 
-    public String getType() {
-        return type;
-    }
+public class DefaultGenerationListener implements GenerationListener {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultGenerationListener.class);
+    private final LinkedList<String> contextStack = new LinkedList<String>();
 
-    public void setType(String type) {
-        this.type = type;
+    public void warning(String message) {
+        LOGGER.warn(String.format("%s: %s", contextStack.getFirst(), message));
     }
 
-    public boolean isWriteable() {
-        return writeable;
+    public void start(String context) {
+        contextStack.addFirst(context);
     }
 
-    public void setWriteable(boolean writeable) {
-        this.writeable = writeable;
+    public void finish() {
+        contextStack.removeFirst();
     }
 }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DocComment.java
similarity index 59%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DocComment.java
index 2a4f998..83baff4 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DocComment.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.dsl.docbook;
 
-import org.gradle.api.Project
+import org.w3c.dom.Node;
 
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
-
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
-
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+public interface DocComment {
+    Iterable<? extends Node> getDocbook();
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DslDocModel.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DslDocModel.groovy
new file mode 100644
index 0000000..1b31d02
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/DslDocModel.groovy
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.XIncludeAwareXmlProvider
+
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.w3c.dom.Document
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import org.gradle.build.docs.dsl.TypeNameResolver
+
+class DslDocModel {
+    private final File classDocbookDir
+    private final Document document
+    private final Iterable<File> classpath
+    private final Map<String, ClassDoc> classes = [:]
+    private final ClassMetaDataRepository<ClassMetaData> classMetaData
+    private final Map<String, ExtensionMetaData> extensionMetaData
+    private final JavadocConverter javadocConverter
+
+    DslDocModel(File classDocbookDir, Document document, Iterable<File> classpath, ClassMetaDataRepository<ClassMetaData> classMetaData, Map<String, ExtensionMetaData> extensionMetaData) {
+        this.classDocbookDir = classDocbookDir
+        this.document = document
+        this.classpath = classpath
+        this.classMetaData = classMetaData
+        this.extensionMetaData = extensionMetaData
+        javadocConverter = new JavadocConverter(document, new JavadocLinkConverter(document, new TypeNameResolver(classMetaData), new LinkRenderer(document, this), classMetaData))
+    }
+
+    boolean isKnownType(String className) {
+        return classMetaData.find(className) != null
+    }
+
+    ClassDoc getClassDoc(String className) {
+        ClassDoc classDoc = classes[className]
+        if (classDoc == null) {
+            classDoc = loadClassDoc(className)
+            classes[className] = classDoc
+        }
+        return classDoc
+    }
+
+    private ClassDoc loadClassDoc(String className) {
+        ClassMetaData classMetaData = classMetaData.find(className)
+        if (!classMetaData) {
+            if (!className.contains('.internal.')) {
+                throw new RuntimeException("No meta-data found for class '$className'.")
+            }
+            classMetaData = new ClassMetaData(className)
+        }
+        try {
+            ExtensionMetaData extensionMetaData = extensionMetaData[className]
+            if (!extensionMetaData) {
+                extensionMetaData = new ExtensionMetaData(className)
+            }
+            File classFile = new File(classDocbookDir, "${className}.xml")
+            if (!classFile.isFile()) {
+                throw new RuntimeException("Docbook source file not found for class '$className' in $classDocbookDir.")
+            }
+            XIncludeAwareXmlProvider provider = new XIncludeAwareXmlProvider(classpath)
+            def doc = new ClassDoc(className, provider.parse(classFile), document, classMetaData, extensionMetaData, this, javadocConverter)
+            doc.mergeContent()
+            return doc
+        } catch (Exception e) {
+            throw new RuntimeException("Could not load the class documentation for class '$className'.", e)
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtensionMetaData.groovy
similarity index 58%
copy from buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtensionMetaData.groovy
index a1681cf..0ae0bf2 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtensionMetaData.groovy
@@ -13,27 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.build.docs.dsl;
+package org.gradle.build.docs.dsl.docbook
 
-import java.io.Serializable;
+import com.google.common.collect.*
 
-public class PropertyMetaData implements Serializable {
-    private String type;
-    private boolean writeable;
+class ExtensionMetaData {
+    final String targetClass
+    final SetMultimap<String, String> extensionClasses = HashMultimap.create()
 
-    public String getType() {
-        return type;
+    ExtensionMetaData(String targetClass) {
+        this.targetClass = targetClass
     }
-
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    public boolean isWriteable() {
-        return writeable;
-    }
-
-    public void setWriteable(boolean writeable) {
-        this.writeable = writeable;
+    
+    def void add(String plugin, String extensionClass) {
+        extensionClasses.put(plugin, extensionClass)
     }
 }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtraAttributeDoc.groovy
similarity index 50%
copy from buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtraAttributeDoc.groovy
index a1681cf..c91cdd2 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/ExtraAttributeDoc.groovy
@@ -13,27 +13,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.build.docs.dsl;
+package org.gradle.build.docs.dsl.docbook
 
-import java.io.Serializable;
+import org.w3c.dom.Element
 
-public class PropertyMetaData implements Serializable {
-    private String type;
-    private boolean writeable;
+class ExtraAttributeDoc {
+    private final Element titleCell
+    private final Element valueCell
 
-    public String getType() {
-        return type;
+    ExtraAttributeDoc(Element titleCell, Element valueCell) {
+        this.titleCell = titleCell
+        this.valueCell = valueCell
     }
 
-    public void setType(String type) {
-        this.type = type;
+    @Override
+    String toString() {
+        return "attribute[key: $key, value: $valueCell.textContent]"
     }
 
-    public boolean isWriteable() {
-        return writeable;
+    String getKey() {
+        return titleCell.textContent
     }
 
-    public void setWriteable(boolean writeable) {
-        this.writeable = writeable;
+    List<Node> getTitle() {
+        return titleCell.childNodes.collect { it }
+    }
+
+    List<Node> getValue() {
+        return valueCell.childNodes.collect { it }
     }
 }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/GenerationListener.java
similarity index 59%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/GenerationListener.java
index 2a4f998..03650b7 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/GenerationListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.dsl.docbook;
 
-import org.gradle.api.Project
+public interface GenerationListener {
+    void warning(String message);
 
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
+    void start(String context);
 
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
-
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+    void finish();
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/HtmlToXmlJavadocLexer.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/HtmlToXmlJavadocLexer.java
new file mode 100644
index 0000000..68dbda0
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/HtmlToXmlJavadocLexer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import java.util.*;
+
+public class HtmlToXmlJavadocLexer implements JavadocLexer {
+    private final JavadocLexer lexer;
+    private final LinkedList<String> elementStack = new LinkedList<String>();
+    private final Set<String> blockElements = new HashSet<String>();
+
+    public HtmlToXmlJavadocLexer(JavadocLexer lexer) {
+        this.lexer = lexer;
+        blockElements.add("p");
+        blockElements.add("pre");
+        blockElements.add("ul");
+        blockElements.add("ol");
+        blockElements.add("li");
+        blockElements.add("h1");
+        blockElements.add("h2");
+        blockElements.add("h3");
+        blockElements.add("h4");
+        blockElements.add("h5");
+        blockElements.add("h6");
+    }
+
+    public void visit(TokenVisitor visitor) {
+        lexer.visit(new VisitorImpl(visitor));
+    }
+
+    private void unwindTo(String element, TokenVisitor visitor) {
+        if (elementStack.contains(element)) {
+            while (!elementStack.getFirst().equals(element)) {
+                visitor.onEndHtmlElement(elementStack.removeFirst());
+            }
+            elementStack.removeFirst();
+            visitor.onEndHtmlElement(element);
+        }
+    }
+
+    private class VisitorImpl extends TokenVisitor {
+        private final TokenVisitor visitor;
+
+        public VisitorImpl(TokenVisitor visitor) {
+            this.visitor = visitor;
+        }
+
+        @Override
+        public void onStartHtmlElement(String name) {
+            if (name.equals("li")) {
+                unwindTo("li", visitor);
+            } else if (blockElements.contains(name)) {
+                unwindTo("p", visitor);
+            }
+            elementStack.addFirst(name);
+            visitor.onStartHtmlElement(name);
+        }
+
+        @Override
+        public void onHtmlElementAttribute(String name, String value) {
+            visitor.onHtmlElementAttribute(name, value);
+        }
+
+        @Override
+        public void onStartHtmlElementComplete(String name) {
+            visitor.onStartHtmlElementComplete(name);
+        }
+
+        @Override
+        public void onEndHtmlElement(String name) {
+            unwindTo(name, visitor);
+            visitor.onEndHtmlElement(name);
+        }
+
+        @Override
+        public void onStartJavadocTag(String name) {
+            visitor.onStartJavadocTag(name);
+        }
+
+        @Override
+        public void onEndJavadocTag(String name) {
+            visitor.onEndJavadocTag(name);
+        }
+
+        @Override
+        public void onText(String text) {
+            visitor.onText(text);
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverter.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverter.java
new file mode 100644
index 0000000..05a7bbb
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverter.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import org.gradle.api.GradleException;
+import org.gradle.build.docs.dsl.model.ClassMetaData;
+import org.gradle.build.docs.dsl.model.MethodMetaData;
+import org.gradle.build.docs.dsl.model.PropertyMetaData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Converts raw javadoc comments into docbook.
+ */
+public class JavadocConverter {
+    private static final Pattern HEADER_PATTERN = Pattern.compile("h(\\d)", Pattern.CASE_INSENSITIVE);
+    private final Document document;
+    private final JavadocLinkConverter linkConverter;
+
+    public JavadocConverter(Document document, JavadocLinkConverter linkConverter) {
+        this.document = document;
+        this.linkConverter = linkConverter;
+    }
+
+    public DocComment parse(ClassMetaData classMetaData, GenerationListener listener) {
+        listener.start(String.format("class %s", classMetaData));
+        try {
+            String rawCommentText = classMetaData.getRawCommentText();
+            try {
+                return parse(rawCommentText, classMetaData, new NoOpCommentSource(), listener);
+            } catch (Exception e) {
+                throw new GradleException(String.format("Could not convert javadoc comment to docbook.%nClass: %s%nComment: %s", classMetaData, rawCommentText), e);
+            }
+        } finally {
+            listener.finish();
+        }
+    }
+
+    public DocComment parse(final PropertyMetaData propertyMetaData, final GenerationListener listener) {
+        listener.start(String.format("property %s", propertyMetaData));
+        try {
+            ClassMetaData ownerClass = propertyMetaData.getOwnerClass();
+            String rawCommentText = propertyMetaData.getRawCommentText();
+            try {
+                CommentSource commentSource = new InheritedPropertyCommentSource(propertyMetaData, listener);
+                DocCommentImpl docComment = parse(rawCommentText, ownerClass, commentSource, listener);
+                adjustGetterComment(docComment);
+                return docComment;
+            } catch (Exception e) {
+                throw new GradleException(String.format("Could not convert javadoc comment to docbook.%nClass: %s%nProperty: %s%nComment: %s", ownerClass.getClassName(), propertyMetaData.getName(), rawCommentText), e);
+            }
+        } finally {
+            listener.finish();
+        }
+    }
+
+    public DocComment parse(final MethodMetaData methodMetaData, final GenerationListener listener) {
+        listener.start(String.format("method %s", methodMetaData));
+        try {
+            ClassMetaData ownerClass = methodMetaData.getOwnerClass();
+            String rawCommentText = methodMetaData.getRawCommentText();
+            try {
+                CommentSource commentSource = new InheritedMethodCommentSource(listener, methodMetaData);
+                return parse(rawCommentText, ownerClass, commentSource, listener);
+            } catch (Exception e) {
+                throw new GradleException(String.format(
+                        "Could not convert javadoc comment to docbook.%nClass: %s%nMethod: %s%nComment: %s",
+                        ownerClass.getClassName(), methodMetaData.getSignature(), rawCommentText), e);
+            }
+        } finally {
+            listener.finish();
+        }
+    }
+
+    private void adjustGetterComment(DocCommentImpl docComment) {
+        // Replace 'Returns the ...' with 'The ...'
+        List<Element> nodes = docComment.getDocbook();
+        if (nodes.isEmpty()) {
+            return;
+        }
+
+        Element firstNode = nodes.get(0);
+        if (!firstNode.getNodeName().equals("para") || !(firstNode.getFirstChild() instanceof Text)) {
+            return;
+        }
+
+        Text comment = (Text) firstNode.getFirstChild();
+        Pattern getterPattern = Pattern.compile("returns\\s+the\\s+", Pattern.CASE_INSENSITIVE);
+        Matcher matcher = getterPattern.matcher(comment.getData());
+        if (matcher.lookingAt()) {
+            comment.setData("The " + comment.getData().substring(matcher.end()));
+        }
+    }
+
+    private DocCommentImpl parse(String rawCommentText, ClassMetaData classMetaData,
+                                 CommentSource inheritedCommentSource, GenerationListener listener) {
+        JavadocLexer lexer = new HtmlToXmlJavadocLexer(new BasicJavadocLexer(new JavadocScanner(rawCommentText)));
+        NodeStack nodes = new NodeStack(document);
+        final HtmlGeneratingTokenHandler handler = new HtmlGeneratingTokenHandler(nodes, document);
+        handler.add(new HtmlElementTranslatingHandler(nodes, document));
+        handler.add(new JavadocTagToElementTranslatingHandler(nodes, document));
+        handler.add(new HeaderHandler(nodes, document));
+        handler.add(new LinkHandler(nodes, linkConverter, classMetaData, listener));
+        handler.add(new InheritDocHandler(nodes, inheritedCommentSource));
+        handler.add(new ValueHtmlElementHandler(nodes, linkConverter, classMetaData, listener));
+        handler.add(new TableHandler(nodes, document));
+        handler.add(new AnchorElementHandler(nodes, document, classMetaData));
+        handler.add(new AToLinkTranslatingHandler(nodes, document, classMetaData));
+        handler.add(new UnknownJavadocTagHandler(nodes, document, listener));
+        handler.add(new UnknownHtmlElementHandler(nodes, document, listener));
+
+        lexer.visit(handler);
+
+        nodes.complete();
+        return new DocCommentImpl(nodes.nodes);
+    }
+
+    private static class DocCommentImpl implements DocComment {
+        private final List<Element> nodes;
+
+        public DocCommentImpl(List<Element> nodes) {
+            this.nodes = nodes;
+        }
+
+        public List<Element> getDocbook() {
+            return nodes;
+        }
+    }
+
+    private static class NodeStack {
+        final Set<String> blockElements = new HashSet<String>();
+        final List<Element> nodes = new ArrayList<Element>();
+        final LinkedList<Element> stack = new LinkedList<Element>();
+        final LinkedList<String> tags = new LinkedList<String>();
+        final Document document;
+
+        private NodeStack(Document document) {
+            this.document = document;
+            blockElements.add("para");
+            blockElements.add("section");
+            blockElements.add("title");
+            blockElements.add("programlisting");
+            blockElements.add("itemizedlist");
+            blockElements.add("orderedlist");
+            blockElements.add("listitem");
+            blockElements.add("table");
+            blockElements.add("tr");
+            blockElements.add("td");
+            blockElements.add("thead");
+        }
+
+        public void appendChild(String text) {
+            if (stack.isEmpty() && text.trim().length() == 0) {
+                return;
+            }
+            appendChild(document.createTextNode(text));
+        }
+
+        public void appendChild(Node node) {
+            boolean blockElement = node instanceof Element && blockElements.contains(node.getNodeName());
+            boolean inlineNode = !blockElement && !(node instanceof Element && node.getNodeName().equals("anchor"));
+            if (blockElement) {
+                endCurrentPara();
+            }
+            if (stack.isEmpty()) {
+                if (!inlineNode) {
+                    appendToResult((Element) node);
+                } else {
+                    Element wrapper = document.createElement("para");
+                    wrapper.appendChild(node);
+                    stack.addFirst(wrapper);
+                    tags.addFirst("");
+                }
+            } else {
+                stack.getFirst().appendChild(node);
+            }
+        }
+
+        public void push(String tag, Element element) {
+            boolean blockElement = blockElements.contains(element.getNodeName());
+            if (blockElement) {
+                endCurrentPara();
+            }
+            if (stack.isEmpty()) {
+                if (blockElement) {
+                    stack.addFirst(element);
+                    tags.addFirst(tag);
+                } else {
+                    Element wrapper = document.createElement("para");
+                    wrapper.appendChild(element);
+                    stack.addFirst(wrapper);
+                    tags.addFirst("");
+                    stack.addFirst(element);
+                    tags.addFirst(tag);
+                }
+            } else {
+                stack.getFirst().appendChild(element);
+                stack.addFirst(element);
+                tags.addFirst(tag);
+            }
+        }
+
+        public Element pop(String tag) {
+            Element element = null;
+            if (!tags.isEmpty() && tags.getFirst().equals(tag)) {
+                element = stack.removeFirst();
+                tags.removeFirst();
+                if (stack.isEmpty()) {
+                    appendToResult(element);
+                }
+            }
+            return element;
+        }
+
+        private void endCurrentPara() {
+            if (stack.isEmpty() || !stack.getFirst().getNodeName().equals("para")) {
+                return;
+            }
+
+            Element para = stack.removeFirst();
+            tags.removeFirst();
+            if (stack.isEmpty()) {
+                appendToResult(para);
+            }
+        }
+
+        private void appendToResult(Element element) {
+            if (element.getFirstChild() == null && element.getAttributes().getLength() == 0) {
+                return;
+            }
+            nodes.add(element);
+        }
+
+        public void complete() {
+            if (!stack.isEmpty()) {
+                appendToResult(stack.getLast());
+            }
+            stack.clear();
+            tags.clear();
+        }
+    }
+
+    private static class HtmlGeneratingTokenHandler extends JavadocLexer.TokenVisitor {
+        final NodeStack nodes;
+        final List<HtmlElementHandler> elementHandlers = new ArrayList<HtmlElementHandler>();
+        final List<JavadocTagHandler> tagHandlers = new ArrayList<JavadocTagHandler>();
+        final LinkedList<HtmlElementHandler> handlerStack = new LinkedList<HtmlElementHandler>();
+        final LinkedList<String> tagStack = new LinkedList<String>();
+        final Map<String, String> attributes = new HashMap<String, String>();
+        StringBuilder tagValue;
+        final Document document;
+
+        public HtmlGeneratingTokenHandler(NodeStack nodes, Document document) {
+            this.nodes = nodes;
+            this.document = document;
+        }
+
+        public void add(HtmlElementHandler handler) {
+            elementHandlers.add(handler);
+        }
+
+        public void add(JavadocTagHandler handler) {
+            tagHandlers.add(handler);
+        }
+
+        @Override
+        void onStartHtmlElement(String name) {
+            attributes.clear();
+        }
+
+        @Override
+        void onHtmlElementAttribute(String name, String value) {
+            attributes.put(name, value);
+        }
+
+        @Override
+        void onStartHtmlElementComplete(String name) {
+            for (HtmlElementHandler handler : elementHandlers) {
+                if (handler.onStartElement(name, attributes)) {
+                    handlerStack.addFirst(handler);
+                    tagStack.addFirst(name);
+                    return;
+                }
+            }
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        void onEndHtmlElement(String name) {
+            if (!tagStack.isEmpty() && tagStack.getFirst().equals(name)) {
+                tagStack.removeFirst();
+                handlerStack.removeFirst().onEndElement(name);
+            }
+        }
+
+        @Override
+        void onStartJavadocTag(String name) {
+            tagValue = new StringBuilder();
+        }
+
+        public void onText(String text) {
+            if (tagValue != null) {
+                tagValue.append(text);
+                return;
+            }
+
+            if (!handlerStack.isEmpty()) {
+                handlerStack.getFirst().onText(text);
+                return;
+            }
+
+            nodes.appendChild(text);
+        }
+
+        @Override
+        void onEndJavadocTag(String name) {
+            for (JavadocTagHandler handler : tagHandlers) {
+                if (handler.onJavadocTag(name, tagValue.toString())) {
+                    tagValue = null;
+                    return;
+                }
+            }
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private interface JavadocTagHandler {
+        boolean onJavadocTag(String tag, String value);
+    }
+
+    private interface HtmlElementHandler {
+        boolean onStartElement(String element, Map<String, String> attributes);
+
+        void onText(String text);
+
+        void onEndElement(String element);
+    }
+
+    private static class UnknownJavadocTagHandler implements JavadocTagHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final GenerationListener listener;
+
+        private UnknownJavadocTagHandler(NodeStack nodes, Document document, GenerationListener listener) {
+            this.nodes = nodes;
+            this.document = document;
+            this.listener = listener;
+        }
+
+        public boolean onJavadocTag(String tag, String value) {
+            listener.warning(String.format("Unsupported Javadoc tag '%s'", tag));
+            Element element = document.createElement("UNHANDLED-TAG");
+            element.appendChild(document.createTextNode(String.format("{@%s %s}", tag, value)));
+            nodes.appendChild(element);
+            return true;
+        }
+    }
+
+    private static class UnknownHtmlElementHandler implements HtmlElementHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final GenerationListener listener;
+
+        private UnknownHtmlElementHandler(NodeStack nodes, Document document, GenerationListener listener) {
+            this.nodes = nodes;
+            this.document = document;
+            this.listener = listener;
+        }
+
+        public boolean onStartElement(String elementName, Map<String, String> attributes) {
+            listener.warning(String.format("Unsupported HTML element <%s>", elementName));
+            Element element = document.createElement("UNHANDLED-ELEMENT");
+            element.appendChild(document.createTextNode(String.format("<%s>", elementName)));
+            nodes.push(elementName, element);
+            return true;
+        }
+
+        public void onText(String text) {
+            nodes.appendChild(text);
+        }
+
+        public void onEndElement(String elementName) {
+            nodes.appendChild(String.format("</%s>", elementName));
+            nodes.pop(elementName);
+        }
+    }
+
+    private static class JavadocTagToElementTranslatingHandler implements JavadocTagHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final Map<String, String> tagToElementMap = new HashMap<String, String>();
+
+        private JavadocTagToElementTranslatingHandler(NodeStack nodes, Document document) {
+            this.nodes = nodes;
+            this.document = document;
+            tagToElementMap.put("code", "literal");
+        }
+
+        public boolean onJavadocTag(String tag, String value) {
+            String elementName = tagToElementMap.get(tag);
+            if (elementName == null) {
+                return false;
+            }
+            Element element = document.createElement(elementName);
+            element.appendChild(document.createTextNode(value));
+            nodes.appendChild(element);
+            return true;
+        }
+    }
+
+    private static class HtmlElementTranslatingHandler implements HtmlElementHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final Map<String, String> elementToElementMap = new HashMap<String, String>();
+
+        private HtmlElementTranslatingHandler(NodeStack nodes, Document document) {
+            this.nodes = nodes;
+            this.document = document;
+            elementToElementMap.put("p", "para");
+            elementToElementMap.put("pre", "programlisting");
+            elementToElementMap.put("ul", "itemizedlist");
+            elementToElementMap.put("ol", "orderedlist");
+            elementToElementMap.put("li", "listitem");
+            elementToElementMap.put("em", "emphasis");
+            elementToElementMap.put("i", "emphasis");
+            elementToElementMap.put("b", "emphasis");
+            elementToElementMap.put("code", "literal");
+        }
+
+        public boolean onStartElement(String element, Map<String, String> attributes) {
+            String newElementName = elementToElementMap.get(element);
+            if (newElementName == null) {
+                return false;
+            }
+            nodes.push(element, document.createElement(newElementName));
+            return true;
+        }
+
+        public void onText(String text) {
+            nodes.appendChild(text);
+        }
+
+        public void onEndElement(String element) {
+            nodes.pop(element);
+        }
+    }
+
+    private static class HeaderHandler implements HtmlElementHandler {
+        final NodeStack nodes;
+        final Document document;
+        int sectionDepth;
+
+        private HeaderHandler(NodeStack nodes, Document document) {
+            this.nodes = nodes;
+            this.document = document;
+        }
+
+        public boolean onStartElement(String element, Map<String, String> attributes) {
+            Matcher matcher = HEADER_PATTERN.matcher(element);
+            if (!matcher.matches()) {
+                return false;
+            }
+            int depth = Integer.parseInt(matcher.group(1));
+            if (sectionDepth == 0) {
+                sectionDepth = depth - 1;
+            }
+            while (sectionDepth >= depth) {
+                nodes.pop("section");
+                sectionDepth--;
+            }
+            Element section = document.createElement("section");
+            while (sectionDepth < depth) {
+                nodes.push("section", section);
+                sectionDepth++;
+            }
+            nodes.push("title", document.createElement("title"));
+            sectionDepth = depth;
+            return true;
+        }
+
+        public void onText(String text) {
+            nodes.appendChild(text);
+        }
+
+        public void onEndElement(String element) {
+            nodes.pop("title");
+        }
+    }
+
+    private static class TableHandler implements HtmlElementHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private Element currentTable;
+        private Element currentRow;
+        private Element header;
+
+        public TableHandler(NodeStack nodes, Document document) {
+            this.nodes = nodes;
+            this.document = document;
+        }
+
+        public boolean onStartElement(String elementName, Map<String, String> attributes) {
+            if (elementName.equals("table")) {
+                if (currentTable != null) {
+                    throw new UnsupportedOperationException("A table within a table is not supported.");
+                }
+                currentTable = document.createElement("table");
+                nodes.push(elementName, currentTable);
+                return true;
+            }
+            if (elementName.equals("tr")) {
+                currentRow = document.createElement("tr");
+                nodes.push(elementName, currentRow);
+                return true;
+            }
+            if (elementName.equals("th")) {
+                if (header == null) {
+                    header = document.createElement("thead");
+                    currentTable.insertBefore(header, null);
+                    header.appendChild(currentRow);
+                }
+                nodes.push(elementName, document.createElement("td"));
+                return true;
+            }
+            if (elementName.equals("td")) {
+                nodes.push(elementName, document.createElement("td"));
+                return true;
+            }
+            return false;
+        }
+
+        public void onEndElement(String elementName) {
+            if (elementName.equals("table")) {
+                currentTable = null;
+                header = null;
+            }
+            if (elementName.equals("tr")) {
+                currentRow = null;
+            }
+            nodes.pop(elementName);
+        }
+
+        public void onText(String text) {
+            nodes.appendChild(text);
+        }
+    }
+
+    private static class AnchorElementHandler implements HtmlElementHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final ClassMetaData classMetaData;
+
+        private AnchorElementHandler(NodeStack nodes, Document document, ClassMetaData classMetaData) {
+            this.nodes = nodes;
+            this.document = document;
+            this.classMetaData = classMetaData;
+        }
+
+        public boolean onStartElement(String elementName, Map<String, String> attributes) {
+            if (!elementName.equals("a") || !attributes.containsKey("name")) {
+                return false;
+            }
+            Element element = document.createElement("anchor");
+            String id = String.format("%s.%s", classMetaData.getClassName(), attributes.get("name"));
+            element.setAttribute("id", id);
+            nodes.appendChild(element);
+            return true;
+        }
+
+        public void onEndElement(String element) {
+        }
+
+        public void onText(String text) {
+        }
+    }
+
+    private static class AToLinkTranslatingHandler implements HtmlElementHandler {
+        private final NodeStack nodes;
+        private final Document document;
+        private final ClassMetaData classMetaData;
+
+        private AToLinkTranslatingHandler(NodeStack nodes, Document document, ClassMetaData classMetaData) {
+            this.nodes = nodes;
+            this.document = document;
+            this.classMetaData = classMetaData;
+        }
+
+        public boolean onStartElement(String elementName, Map<String, String> attributes) {
+            if (!elementName.equals("a") || !attributes.containsKey("href")) {
+                return false;
+            }
+            String href = attributes.get("href");
+            if (!href.startsWith("#")) {
+                return false;
+            }
+            Element element = document.createElement("link");
+            String targetId = String.format("%s.%s", classMetaData.getClassName(), href.substring(1));
+            element.setAttribute("linkend", targetId);
+            nodes.push(elementName, element);
+            return true;
+        }
+
+        public void onEndElement(String element) {
+            nodes.pop(element);
+        }
+
+        public void onText(String text) {
+            nodes.appendChild(text);
+        }
+    }
+
+    private static class ValueHtmlElementHandler implements JavadocTagHandler {
+        private final JavadocLinkConverter linkConverter;
+        private final ClassMetaData classMetaData;
+        private final NodeStack nodes;
+        private final GenerationListener listener;
+
+        public ValueHtmlElementHandler(NodeStack nodes, JavadocLinkConverter linkConverter, ClassMetaData classMetaData,
+                                       GenerationListener listener) {
+            this.nodes = nodes;
+            this.linkConverter = linkConverter;
+            this.classMetaData = classMetaData;
+            this.listener = listener;
+        }
+
+        public boolean onJavadocTag(String tag, String value) {
+            if (!tag.equals("value")) {
+                return false;
+            }
+            nodes.appendChild(linkConverter.resolveValue(value, classMetaData, listener));
+            return true;
+        }
+    }
+
+    private static class LinkHandler implements JavadocTagHandler {
+        private final NodeStack nodes;
+        private final JavadocLinkConverter linkConverter;
+        private final ClassMetaData classMetaData;
+        private final GenerationListener listener;
+
+        private LinkHandler(NodeStack nodes, JavadocLinkConverter linkConverter, ClassMetaData classMetaData,
+                            GenerationListener listener) {
+            this.nodes = nodes;
+            this.linkConverter = linkConverter;
+            this.classMetaData = classMetaData;
+            this.listener = listener;
+        }
+
+        public boolean onJavadocTag(String tag, String value) {
+            if (!tag.equals("link")) {
+                return false;
+            }
+            nodes.appendChild(linkConverter.resolve(value, classMetaData, listener));
+            return true;
+        }
+    }
+
+    private static class InheritDocHandler implements JavadocTagHandler {
+        private final CommentSource source;
+        private final NodeStack nodeStack;
+
+        private InheritDocHandler(NodeStack nodeStack, CommentSource source) {
+            this.nodeStack = nodeStack;
+            this.source = source;
+        }
+
+        public boolean onJavadocTag(String tag, String value) {
+            if (!tag.equals("inheritDoc")) {
+                return false;
+            }
+            for (Node node : source.getCommentText()) {
+                nodeStack.appendChild(node);
+            }
+            return true;
+        }
+    }
+
+    private interface CommentSource {
+        Iterable<? extends Node> getCommentText();
+    }
+
+    private static class NoOpCommentSource implements CommentSource {
+        public List<? extends Node> getCommentText() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private class InheritedPropertyCommentSource implements CommentSource {
+        private final PropertyMetaData propertyMetaData;
+        private final GenerationListener listener;
+
+        public InheritedPropertyCommentSource(PropertyMetaData propertyMetaData, GenerationListener listener) {
+            this.propertyMetaData = propertyMetaData;
+            this.listener = listener;
+        }
+
+        public Iterable<? extends Node> getCommentText() {
+            PropertyMetaData overriddenProperty = propertyMetaData.getOverriddenProperty();
+            if (overriddenProperty == null) {
+                listener.warning("No inherited javadoc comment found.");
+                return Arrays.asList(document.createTextNode("!!NO INHERITED DOC COMMENT!!"));
+            }
+            return parse(overriddenProperty, listener).getDocbook();
+        }
+    }
+
+    private class InheritedMethodCommentSource implements CommentSource {
+        private final GenerationListener listener;
+        private final MethodMetaData methodMetaData;
+
+        public InheritedMethodCommentSource(GenerationListener listener, MethodMetaData methodMetaData) {
+            this.listener = listener;
+            this.methodMetaData = methodMetaData;
+        }
+
+        public Iterable<? extends Node> getCommentText() {
+            MethodMetaData overriddenMethod = methodMetaData.getOverriddenMethod();
+            if (overriddenMethod == null) {
+                listener.warning("No inherited javadoc comment found.");
+                return Arrays.asList(document.createTextNode("!!NO INHERITED DOC COMMENT!!"));
+            }
+
+            return parse(overriddenMethod, listener).getDocbook();
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLexer.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLexer.java
new file mode 100644
index 0000000..05a623d
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLexer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+public interface JavadocLexer {
+    /**
+     * Visits the tokens in the input stream for this lexer. Reads to the end of the input.
+     */
+    void visit(TokenVisitor visitor);
+
+    class TokenVisitor {
+        void onStartHtmlElement(String name) {
+        }
+
+        void onHtmlElementAttribute(String name, String value) {
+        }
+
+        void onStartHtmlElementComplete(String name) {
+        }
+
+        void onEndHtmlElement(String name) {
+        }
+
+        void onStartJavadocTag(String name) {
+        }
+
+        void onEndJavadocTag(String name) {
+        }
+
+        void onText(String text) {
+        }
+    }
+
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverter.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverter.java
new file mode 100644
index 0000000..fb14df8
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverter.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import org.gradle.build.docs.dsl.TypeNameResolver;
+import org.gradle.build.docs.dsl.model.ClassMetaData;
+import org.gradle.build.docs.dsl.model.MethodMetaData;
+import org.gradle.build.docs.dsl.model.TypeMetaData;
+import org.gradle.build.docs.model.ClassMetaDataRepository;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Converts a javadoc link into docbook.
+ */
+public class JavadocLinkConverter {
+    private final Pattern linkPattern = Pattern.compile("(?s)\\s*([\\w\\.]*)(#(\\w+)(\\((.*)\\))?)?.*");
+    private final Document document;
+    private final TypeNameResolver typeNameResolver;
+    private final LinkRenderer linkRenderer;
+    private final ClassMetaDataRepository<ClassMetaData> repository;
+
+    public JavadocLinkConverter(Document document, TypeNameResolver typeNameResolver, LinkRenderer linkRenderer,
+                                ClassMetaDataRepository<ClassMetaData> repository) {
+        this.document = document;
+        this.typeNameResolver = typeNameResolver;
+        this.linkRenderer = linkRenderer;
+        this.repository = repository;
+    }
+
+    /**
+     * Converts a javadoc link into docbook.
+     */
+    public Node resolve(String link, ClassMetaData classMetaData, GenerationListener listener) {
+        Node node = doResolve(link, classMetaData, listener);
+        if (node != null) {
+            return node;
+        }
+
+        listener.warning(String.format("Could not convert Javadoc link '%s'", link));
+        Element element = document.createElement("UNHANDLED-LINK");
+        element.appendChild(document.createTextNode(link));
+        return element;
+    }
+
+    private Node doResolve(String link, ClassMetaData classMetaData, GenerationListener listener) {
+        Matcher matcher = linkPattern.matcher(link);
+        if (!matcher.matches()) {
+            return null;
+        }
+
+        String className = null;
+        if (matcher.group(1).length() > 0) {
+            className = typeNameResolver.resolve(matcher.group(1), classMetaData);
+            if (className == null) {
+                return null;
+            }
+        }
+        if (matcher.group(2) == null) {
+            return linkRenderer.link(new TypeMetaData(className), listener);
+        }
+
+        ClassMetaData targetClass;
+        if (className != null) {
+            targetClass = repository.find(className);
+            if (targetClass == null) {
+                return null;
+            }
+        } else {
+            targetClass = classMetaData;
+        }
+
+        String methodSignature = matcher.group(3);
+        if (matcher.group(5) != null) {
+            StringBuilder signature = new StringBuilder();
+            signature.append(methodSignature);
+            signature.append("(");
+            if (matcher.group(5).length() > 0) {
+                String[] types = matcher.group(5).split(",\\s*");
+                for (int i = 0; i < types.length; i++) {
+                    String type = types[i];
+                    Matcher typeMatcher = Pattern.compile("(\\w+)(.*)").matcher(type);
+                    if (!typeMatcher.matches()) {
+                        return null;
+                    }
+                    if (i > 0) {
+                        signature.append(", ");
+                    }
+                    signature.append(typeNameResolver.resolve(typeMatcher.group(1), classMetaData));
+                    signature.append(typeMatcher.group(2));
+                }
+            }
+            signature.append(")");
+            methodSignature = signature.toString();
+        }
+
+        MethodMetaData method = findMethod(methodSignature, targetClass);
+        if (method == null) {
+            return null;
+        }
+
+        return linkRenderer.link(method, listener);
+    }
+
+    private MethodMetaData findMethod(String name, ClassMetaData targetClass) {
+        List<MethodMetaData> candidates = new ArrayList<MethodMetaData>();
+        for (MethodMetaData methodMetaData : targetClass.getDeclaredMethods()) {
+            if (name.equals(methodMetaData.getOverrideSignature())) {
+                return methodMetaData;
+            }
+            if (name.equals(methodMetaData.getName())) {
+                candidates.add(methodMetaData);
+            }
+        }
+
+        if (candidates.size() != 1) {
+            return null;
+        }
+        return candidates.get(0);
+    }
+
+    /**
+     * Converts a javadoc value link into docbook.
+     */
+    public Node resolveValue(String fieldName, ClassMetaData classMetaData, GenerationListener listener) {
+        String[] parts = fieldName.split("#");
+        ClassMetaData targetClass;
+        if (parts[0].length() > 0) {
+            String targetClassName = typeNameResolver.resolve(parts[0], classMetaData);
+            targetClass = repository.find(targetClassName);
+            if (targetClass == null) {
+                listener.warning(String.format("Could not local target class '%s' for field value link '%s'", targetClass, fieldName));
+                Element element = document.createElement("UNHANDLED-VALUE");
+                element.appendChild(document.createTextNode(targetClassName + ":" + parts[1]));
+                return element;
+            }
+        } else {
+            targetClass = classMetaData;
+        }
+
+        String value = targetClass.getConstants().get(parts[1]);
+        if (value == null) {
+            listener.warning(String.format("Field '%s' does not have any value", fieldName));
+            Element element = document.createElement("NO-VALUE-FOR_FIELD");
+            element.appendChild(document.createTextNode(targetClass.getClassName() + ":" + parts[1]));
+            return element;
+        }
+
+        Element element = document.createElement("literal");
+        element.appendChild(document.createTextNode(value));
+        return element;
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocScanner.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocScanner.java
new file mode 100644
index 0000000..cf0b342
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/JavadocScanner.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import org.gradle.util.UncheckedException;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Extracts the main description of a javadoc comment from its raw text, as a stream of characters. See
+ * http://download.oracle.com/javase/1.5.0/docs/tooldocs/solaris/javadoc.html#documentationcomments for details.
+ *
+ * <ul>
+ * <li>Removes leading '*' characters.</li>
+ * <li>Removes block tags.</li>
+ * <li>Removes leading and trailing empty lines.</li>
+ * </ul>
+ */
+class JavadocScanner {
+    private final StringBuilder input = new StringBuilder();
+    private int pos;
+    private int markPos;
+
+    JavadocScanner(String rawCommentText) {
+        pushText(rawCommentText);
+    }
+
+    @Override
+    public String toString() {
+        return input.substring(pos);
+    }
+
+    public boolean isEmpty() {
+        return pos == input.length();
+    }
+
+    public void mark() {
+        markPos = pos;
+    }
+
+    public void next() {
+        next(1);
+    }
+
+    public void next(int n) {
+        pos += n;
+    }
+
+    public boolean lookingAt(char c) {
+        return input.charAt(pos) == c;
+    }
+
+    public boolean lookingAt(CharSequence prefix) {
+        int i = 0;
+        int cpos = pos;
+        while (i < prefix.length() && cpos < input.length()) {
+            if (prefix.charAt(i) != input.charAt(cpos)) {
+                return false;
+            }
+            i++;
+            cpos++;
+        }
+        return true;
+    }
+
+    public boolean lookingAt(Pattern pattern) {
+        Matcher m = pattern.matcher(input);
+        m.region(pos, input.length());
+        return m.lookingAt();
+    }
+
+    public String region() {
+        return input.substring(markPos, pos);
+    }
+
+    /**
+     * Moves the position to the next instance of the given character, or the end of the input if not found.
+     */
+    public void find(char c) {
+        int cpos = pos;
+        while (cpos < input.length()) {
+            if (input.charAt(cpos) == c) {
+                break;
+            }
+            cpos++;
+        }
+        pos = cpos;
+    }
+
+    /**
+     * Moves the position to the start of the next instance of the given pattern, or the end of the input if not
+     * found.
+     */
+    public void find(Pattern pattern) {
+        Matcher m = pattern.matcher(input);
+        m.region(pos, input.length());
+        if (m.find()) {
+            pos = m.start();
+        } else {
+            pos = input.length();
+        }
+    }
+
+    /**
+     * Moves the position over the given pattern if currently looking at the pattern. Does nothing if not.
+     */
+    public void skip(Pattern pattern) {
+        Matcher m = pattern.matcher(input);
+        m.region(pos, input.length());
+        if (m.lookingAt()) {
+            pos = m.end();
+        }
+    }
+
+    public void pushText(String rawCommentText) {
+        if (rawCommentText == null) {
+            return;
+        }
+
+        StringBuilder builder = new StringBuilder();
+        try {
+            BufferedReader reader = new BufferedReader(new StringReader(rawCommentText));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                line = line.replaceFirst("\\s*\\*\\s*", "");
+                if (line.startsWith("@")) {
+                    // Ignore the tag section of the comment
+                    break;
+                }
+                builder.append(line);
+                builder.append("\n");
+            }
+        } catch (IOException e) {
+            throw UncheckedException.asUncheckedException(e);
+        }
+        input.insert(pos, builder.toString().trim());
+    }
+
+    public char getFirst() {
+        return input.charAt(pos);
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/LinkRenderer.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/LinkRenderer.java
new file mode 100644
index 0000000..dd11c54
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/LinkRenderer.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook;
+
+import org.apache.commons.lang.StringUtils;
+import org.gradle.build.docs.dsl.model.MethodMetaData;
+import org.gradle.build.docs.dsl.model.TypeMetaData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class LinkRenderer {
+    private final Document document;
+    private final DslDocModel model;
+    private final Set<String> primitiveTypes = new HashSet<String>();
+
+    public LinkRenderer(Document document, DslDocModel model) {
+        this.document = document;
+        this.model = model;
+        primitiveTypes.add("boolean");
+        primitiveTypes.add("byte");
+        primitiveTypes.add("short");
+        primitiveTypes.add("int");
+        primitiveTypes.add("long");
+        primitiveTypes.add("char");
+        primitiveTypes.add("float");
+        primitiveTypes.add("double");
+        primitiveTypes.add("void");
+    }
+
+    Node link(TypeMetaData type, final GenerationListener listener) {
+        final Element linkElement = document.createElement("classname");
+
+        type.visitSignature(new TypeMetaData.SignatureVisitor() {
+            public void visitText(String text) {
+                linkElement.appendChild(document.createTextNode(text));
+            }
+
+            public void visitType(String name) {
+                linkElement.appendChild(addType(name, listener));
+            }
+        });
+
+        linkElement.normalize();
+        if (linkElement.getChildNodes().getLength() == 1 && linkElement.getFirstChild() instanceof Element) {
+            return linkElement.getFirstChild();
+        }
+        return linkElement;
+    }
+
+    private Node addType(String className, GenerationListener listener) {
+        if (model.isKnownType(className)) {
+            Element linkElement = document.createElement("apilink");
+            linkElement.setAttribute("class", className);
+            return linkElement;
+        }
+
+        if (primitiveTypes.contains(className)) {
+            Element classNameElement = document.createElement("classname");
+            classNameElement.appendChild(document.createTextNode(className));
+            return classNameElement;
+        }
+
+        if (className.startsWith("java.")) {
+            Element linkElement = document.createElement("ulink");
+            linkElement.setAttribute("url", String.format("http://download.oracle.com/javase/1.5.0/docs/api/%s.html",
+                    className.replace(".", "/")));
+            Element classNameElement = document.createElement("classname");
+            classNameElement.appendChild(document.createTextNode(StringUtils.substringAfterLast(className, ".")));
+            linkElement.appendChild(classNameElement);
+            return linkElement;
+        }
+
+        if (className.startsWith("groovy.")) {
+            Element linkElement = document.createElement("ulink");
+            linkElement.setAttribute("url", String.format("http://groovy.codehaus.org/gapi/%s.html", className.replace(
+                    ".", "/")));
+            Element classNameElement = document.createElement("classname");
+            classNameElement.appendChild(document.createTextNode(StringUtils.substringAfterLast(className, ".")));
+            linkElement.appendChild(classNameElement);
+            return linkElement;
+        }
+
+        listener.warning(String.format("Could not generate link for unknown class '%s'", className));
+        Element element = document.createElement("classname");
+        element.appendChild(document.createTextNode(className));
+        return element;
+    }
+
+    public Node link(MethodMetaData method, GenerationListener listener) {
+        if (model.isKnownType(method.getOwnerClass().getClassName())) {
+            Element apilink = document.createElement("apilink");
+            apilink.setAttribute("class", method.getOwnerClass().getClassName());
+            apilink.setAttribute("method", method.getOverrideSignature());
+            return apilink;
+        } else {
+            listener.warning(String.format("Could not generate link for method %s", method));
+            Element element = document.createElement("UNKNOWN-METHOD");
+            element.appendChild(document.createTextNode(String.format("%s.%s()", method.getOwnerClass().getClassName(),
+                    method.getName())));
+            return element;
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/MethodDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/MethodDoc.groovy
new file mode 100644
index 0000000..81816db
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/MethodDoc.groovy
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.dsl.model.MethodMetaData
+import org.w3c.dom.Element
+
+class MethodDoc {
+    private final String id
+    private final MethodMetaData metaData
+    private final List<Element> comment
+
+    MethodDoc(MethodMetaData metaData, List<Element> comment) {
+        this(metaData.ownerClass, metaData, comment)
+    }
+
+    MethodDoc(ClassMetaData referringClass, MethodMetaData metaData, List<Element> comment) {
+        this.metaData = metaData
+        id = "$referringClass.className:$metaData.overrideSignature"
+        this.comment = comment
+    }
+
+    MethodDoc forClass(ClassMetaData c) {
+        return new MethodDoc(c, metaData, comment)
+    }
+
+    String getId() {
+        return id
+    }
+
+    String getName() {
+        return metaData.name
+    }
+
+    MethodMetaData getMetaData() {
+        return metaData
+    }
+
+    Element getDescription() {
+        return comment.find { it.nodeName == 'para' }
+    }
+    
+    List<Element> getComment() {
+        return comment
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/PropertyDoc.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/PropertyDoc.groovy
new file mode 100644
index 0000000..3af0131
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/docbook/PropertyDoc.groovy
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.model.PropertyMetaData
+import org.w3c.dom.Element
+import org.gradle.build.docs.dsl.model.ClassMetaData
+
+class PropertyDoc {
+    private final String id
+    private final String name
+    private final List<Element> comment
+    private final List<ExtraAttributeDoc> additionalValues
+    private final PropertyMetaData metaData
+
+    PropertyDoc(PropertyMetaData propertyMetaData, List<Element> comment, List<ExtraAttributeDoc> additionalValues) {
+        this(propertyMetaData.ownerClass, propertyMetaData, comment, additionalValues)
+    }
+
+    PropertyDoc(ClassMetaData referringClass, PropertyMetaData propertyMetaData, List<Element> comment, List<ExtraAttributeDoc> additionalValues) {
+        name = propertyMetaData.name
+        this.metaData = propertyMetaData
+        id = "${referringClass.className}:$name"
+        this.comment = comment
+        this.additionalValues = additionalValues
+    }
+
+    PropertyDoc forClass(ClassMetaData classMetaData, List<ExtraAttributeDoc> additionalValues) {
+        return new PropertyDoc(classMetaData, metaData, comment, additionalValues)
+    }
+
+    String getId() {
+        return id
+    }
+
+    String getName() {
+        return name
+    }
+
+    PropertyMetaData getMetaData() {
+        return metaData
+    }
+
+    Element getDescription() {
+        return comment.find { it.nodeName == 'para' }
+    }
+
+    List<Element> getComment() {
+        return comment
+    }
+
+    List<ExtraAttributeDoc> getAdditionalValues() {
+        return additionalValues
+    }
+}
+
+
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ClassMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ClassMetaData.java
new file mode 100644
index 0000000..5e3c664
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ClassMetaData.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model;
+
+import org.apache.commons.lang.StringUtils;
+import org.gradle.api.Action;
+import org.gradle.build.docs.model.Attachable;
+import org.gradle.build.docs.model.ClassMetaDataRepository;
+import org.gradle.util.GUtil;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class ClassMetaData implements Serializable, Attachable<ClassMetaData>, LanguageElement, TypeContainer {
+    private final String className;
+    private String superClassName;
+    private final String packageName;
+    private final boolean isInterface;
+    private final boolean isGroovy;
+    private final String rawCommentText;
+    private final List<String> imports = new ArrayList<String>();
+    private final List<String> interfaceNames = new ArrayList<String>();
+    private final Map<String, PropertyMetaData> declaredProperties = new HashMap<String, PropertyMetaData>();
+    private final Set<MethodMetaData> declaredMethods = new HashSet<MethodMetaData>();
+    private final List<String> innerClassNames = new ArrayList<String>();
+    private String outerClassName;
+    private transient ClassMetaDataRepository<ClassMetaData> metaDataRepository;
+    public final HashMap<String,String> constants = new HashMap<String, String>();
+
+    public ClassMetaData(String className, String packageName, boolean isInterface, boolean isGroovy, String rawClassComment) {
+        this.className = className;
+        this.packageName = packageName;
+        this.isInterface = isInterface;
+        this.isGroovy = isGroovy;
+        this.rawCommentText = rawClassComment;
+    }
+
+    public ClassMetaData(String className) {
+        this(className, StringUtils.substringBeforeLast(className, "."), false, false, "");
+    }
+
+    @Override
+    public String toString() {
+        return className;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public String getSimpleName() {
+        return StringUtils.substringAfterLast(className, ".");
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public boolean isInterface() {
+        return isInterface;
+    }
+
+    public boolean isGroovy() {
+        return isGroovy;
+    }
+
+    public String getSuperClassName() {
+        return superClassName;
+    }
+
+    public void setSuperClassName(String superClassName) {
+        this.superClassName = superClassName;
+    }
+
+    public ClassMetaData getSuperClass() {
+        return superClassName == null ? null : metaDataRepository.find(superClassName);
+    }
+
+    public List<String> getInterfaceNames() {
+        return interfaceNames;
+    }
+
+    public void addInterfaceName(String name) {
+        interfaceNames.add(name);
+    }
+
+    public List<ClassMetaData> getInterfaces() {
+        List<ClassMetaData> interfaces = new ArrayList<ClassMetaData>();
+        for (String interfaceName : interfaceNames) {
+            ClassMetaData interfaceMetaData = metaDataRepository.find(interfaceName);
+            if (interfaceMetaData != null) {
+                interfaces.add(interfaceMetaData);
+            }
+        }
+        return interfaces;
+    }
+
+    public List<String> getInnerClassNames() {
+        return innerClassNames;
+    }
+
+    public void addInnerClassName(String innerClassName) {
+        innerClassNames.add(innerClassName);
+    }
+
+    public String getOuterClassName() {
+        return outerClassName;
+    }
+
+    public void setOuterClassName(String outerClassName) {
+        this.outerClassName = outerClassName;
+    }
+
+    public String getRawCommentText() {
+        return rawCommentText;
+    }
+
+    public List<String> getImports() {
+        return imports;
+    }
+
+    public void addImport(String importName) {
+        imports.add(importName);
+    }
+
+    public PropertyMetaData addReadableProperty(String name, TypeMetaData type, String rawCommentText, MethodMetaData getterMethod) {
+        PropertyMetaData property = getProperty(name);
+        property.setType(type);
+        property.setRawCommentText(rawCommentText);
+        property.setGetter(getterMethod);
+        return property;
+    }
+
+    public PropertyMetaData addWriteableProperty(String name, TypeMetaData type, String rawCommentText, MethodMetaData setterMethod) {
+        PropertyMetaData property = getProperty(name);
+        if (property.getType() == null) {
+            property.setType(type);
+        }
+        if (!GUtil.isTrue(property.getRawCommentText())) {
+            property.setRawCommentText(rawCommentText);
+        }
+        property.setSetter(setterMethod);
+        return property;
+    }
+
+    public PropertyMetaData findDeclaredProperty(String name) {
+        return declaredProperties.get(name);
+    }
+
+    public Set<String> getDeclaredPropertyNames() {
+        return declaredProperties.keySet();
+    }
+
+    public Set<PropertyMetaData> getDeclaredProperties() {
+        return new HashSet<PropertyMetaData>(declaredProperties.values());
+    }
+
+    public Set<MethodMetaData> getDeclaredMethods() {
+        return declaredMethods;
+    }
+
+    public MethodMetaData findDeclaredMethod(String signature) {
+        for (MethodMetaData method : declaredMethods) {
+            if (method.getOverrideSignature().equals(signature)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds a property by name. Includes inherited properties.
+     *
+     * @param name The property name.
+     * @return The property, or null if no such property exists.
+     */
+    public PropertyMetaData findProperty(String name) {
+        PropertyMetaData propertyMetaData = declaredProperties.get(name);
+        if (propertyMetaData != null) {
+            return propertyMetaData;
+        }
+        ClassMetaData superClass = getSuperClass();
+        if (superClass != null) {
+            return superClass.findProperty(name);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the set of property names for this class, including inherited properties.
+     *
+     * @return The set of property names.
+     */
+    public Set<String> getPropertyNames() {
+        Set<String> propertyNames = new TreeSet<String>();
+        propertyNames.addAll(declaredProperties.keySet());
+        ClassMetaData superClass = getSuperClass();
+        if (superClass != null) {
+            propertyNames.addAll(superClass.getPropertyNames());
+        }
+        return propertyNames;
+    }
+
+    private PropertyMetaData getProperty(String name) {
+        PropertyMetaData property = declaredProperties.get(name);
+        if (property == null) {
+            property = new PropertyMetaData(name, this);
+            declaredProperties.put(name, property);
+        }
+        return property;
+    }
+
+    public Map<String, String> getConstants() {
+        return constants;
+    }
+    
+    public void attach(ClassMetaDataRepository<ClassMetaData> metaDataRepository) {
+        this.metaDataRepository = metaDataRepository;
+    }
+
+    public MethodMetaData addMethod(String name, TypeMetaData returnType, String rawCommentText) {
+        MethodMetaData method = new MethodMetaData(name, this);
+        declaredMethods.add(method);
+        method.setReturnType(returnType);
+        method.setRawCommentText(rawCommentText);
+        return method;
+    }
+
+    public void visitTypes(Action<TypeMetaData> action) {
+        for (PropertyMetaData propertyMetaData : declaredProperties.values()) {
+            propertyMetaData.visitTypes(action);
+        }
+        for (MethodMetaData methodMetaData : declaredMethods) {
+            methodMetaData.visitTypes(action);
+        }
+    }
+}
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/LanguageElement.java
similarity index 58%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/LanguageElement.java
index 2a4f998..5fc9d64 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/LanguageElement.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.dsl.model;
 
-import org.gradle.api.Project
-
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
-
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
-
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+public interface LanguageElement {
+    String getRawCommentText();
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/MethodMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/MethodMetaData.java
new file mode 100644
index 0000000..9423e8d
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/MethodMetaData.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model;
+
+import org.gradle.api.Action;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+public class MethodMetaData implements Serializable, LanguageElement, TypeContainer {
+    private final String name;
+    private final ClassMetaData ownerClass;
+    private final List<ParameterMetaData> parameters = new ArrayList<ParameterMetaData>();
+    private String rawCommentText;
+    private TypeMetaData returnType;
+
+    public MethodMetaData(String name, ClassMetaData ownerClass) {
+        this.name = name;
+        this.ownerClass = ownerClass;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s.%s()", ownerClass, name);
+    }
+
+    public ClassMetaData getOwnerClass() {
+        return ownerClass;
+    }
+
+    public TypeMetaData getReturnType() {
+        return returnType;
+    }
+
+    public void setReturnType(TypeMetaData returnType) {
+        this.returnType = returnType;
+    }
+
+    public MethodMetaData getOverriddenMethod() {
+        LinkedList<ClassMetaData> queue = new LinkedList<ClassMetaData>();
+        queue.add(ownerClass.getSuperClass());
+        queue.addAll(ownerClass.getInterfaces());
+        
+        String overrideSignature = getOverrideSignature();
+
+        while (!queue.isEmpty()) {
+            ClassMetaData cl = queue.removeFirst();
+            if (cl == null) {
+                continue;
+            }
+            MethodMetaData overriddenMethod = cl.findDeclaredMethod(overrideSignature);
+            if (overriddenMethod != null) {
+                return overriddenMethod;
+            }
+            queue.add(cl.getSuperClass());
+            queue.addAll(cl.getInterfaces());
+        }
+
+        return null;
+    }
+
+    public List<ParameterMetaData> getParameters() {
+        return parameters;
+    }
+
+    public ParameterMetaData addParameter(String name, TypeMetaData type) {
+        ParameterMetaData param = new ParameterMetaData(name, this);
+        param.setType(type);
+        parameters.add(param);
+        return param;
+    }
+    
+    public String getRawCommentText() {
+        return rawCommentText;
+    }
+
+    public void setRawCommentText(String rawCommentText) {
+        this.rawCommentText = rawCommentText;
+    }
+
+    public String getSignature() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(returnType.getSignature());
+        builder.append(' ');
+        builder.append(name);
+        builder.append('(');
+        for (int i = 0; i < parameters.size(); i++) {
+            ParameterMetaData param =  parameters.get(i);
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(param.getSignature());
+        }
+        builder.append(')');
+        return builder.toString();
+    }
+
+    public String getOverrideSignature() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(name);
+        builder.append('(');
+        for (int i = 0; i < parameters.size(); i++) {
+            ParameterMetaData param =  parameters.get(i);
+            if (i > 0) {
+                builder.append(", ");
+            }
+            builder.append(param.getType().getRawType().getSignature());
+        }
+        builder.append(')');
+        return builder.toString();
+    }
+
+    public void visitTypes(Action<TypeMetaData> action) {
+        action.execute(returnType);
+        for (ParameterMetaData parameter : parameters) {
+            parameter.visitTypes(action);
+        }
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ParameterMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ParameterMetaData.java
new file mode 100644
index 0000000..ff54140
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/ParameterMetaData.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model;
+
+import org.gradle.api.Action;
+
+import java.io.Serializable;
+
+public class ParameterMetaData implements Serializable, TypeContainer {
+    private final MethodMetaData ownerMethod;
+    private final String name;
+    private TypeMetaData type;
+
+    public ParameterMetaData(String name, MethodMetaData ownerMethod) {
+        this.name = name;
+        this.ownerMethod = ownerMethod;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public TypeMetaData getType() {
+        return type;
+    }
+
+    public void setType(TypeMetaData type) {
+        this.type = type;
+    }
+
+    public String getSignature() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type.getSignature());
+        builder.append(" ");
+        builder.append(name);
+        return builder.toString();
+    }
+
+    public void visitTypes(Action<TypeMetaData> action) {
+        action.execute(type);
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/PropertyMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/PropertyMetaData.java
new file mode 100644
index 0000000..fb3ae2f
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/PropertyMetaData.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model;
+
+import org.gradle.api.Action;
+
+import java.io.Serializable;
+
+public class PropertyMetaData implements Serializable, LanguageElement, TypeContainer {
+    private TypeMetaData type;
+    private String rawCommentText;
+    private final String name;
+    private final ClassMetaData ownerClass;
+    private MethodMetaData setter;
+    private MethodMetaData getter;
+
+    public PropertyMetaData(String name, ClassMetaData ownerClass) {
+        this.name = name;
+        this.ownerClass = ownerClass;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s.%s", ownerClass, name);
+    }
+
+    public TypeMetaData getType() {
+        return type;
+    }
+
+    public void setType(TypeMetaData type) {
+        this.type = type;
+    }
+
+    public boolean isWriteable() {
+        return setter != null;
+    }
+
+    public ClassMetaData getOwnerClass() {
+        return ownerClass;
+    }
+
+    public String getRawCommentText() {
+        return rawCommentText;
+    }
+
+    public void setRawCommentText(String rawCommentText) {
+        this.rawCommentText = rawCommentText;
+    }
+
+    public String getSignature() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(type.getSignature());
+        builder.append(' ');
+        builder.append(name);
+        return builder.toString();
+    }
+
+    public MethodMetaData getGetter() {
+        return getter;
+    }
+
+    public void setGetter(MethodMetaData getter) {
+        this.getter = getter;
+    }
+
+    public MethodMetaData getSetter() {
+        return setter;
+    }
+
+    public void setSetter(MethodMetaData setter) {
+        this.setter = setter;
+    }
+
+    public PropertyMetaData getOverriddenProperty() {
+        MethodMetaData overriddenMethod = null;
+        if (getter != null) {
+            overriddenMethod = getter.getOverriddenMethod();
+        }
+        if (overriddenMethod == null && setter != null) {
+            overriddenMethod = setter.getOverriddenMethod();
+        }
+        if (overriddenMethod != null) {
+            return overriddenMethod.getOwnerClass().findDeclaredProperty(name);
+        }
+
+        return null;
+    }
+
+    public void visitTypes(Action<TypeMetaData> action) {
+        action.execute(type);
+    }
+}
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeContainer.java
similarity index 59%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeContainer.java
index 2a4f998..2a86013 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeContainer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.dsl.model;
 
-import org.gradle.api.Project
+import org.gradle.api.Action;
 
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
-
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
-
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+public interface TypeContainer {
+    void visitTypes(Action<TypeMetaData> action);
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeMetaData.java b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeMetaData.java
new file mode 100644
index 0000000..fbfd7a9
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/model/TypeMetaData.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model;
+
+import org.gradle.api.Action;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class TypeMetaData implements Serializable, TypeContainer {
+    public static final TypeMetaData VOID = new TypeMetaData("void");
+    public static final TypeMetaData OBJECT = new TypeMetaData("java.lang.Object");
+
+    private String name;
+    private int arrayDimensions;
+    private boolean varargs;
+    private List<TypeMetaData> typeArgs;
+    private boolean wildcard;
+    private TypeMetaData upperBounds;
+    private TypeMetaData lowerBounds;
+
+    public TypeMetaData(String name) {
+        this.name = name;
+    }
+
+    public TypeMetaData() {
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getArrayDimensions() {
+        return arrayDimensions + (varargs ? 1 : 0);
+    }
+
+    public TypeMetaData addArrayDimension() {
+        arrayDimensions++;
+        return this;
+    }
+
+    public boolean isVarargs() {
+        return varargs;
+    }
+
+    public TypeMetaData setVarargs() {
+        this.varargs = true;
+        return this;
+    }
+
+    public TypeMetaData getRawType() {
+        if (wildcard || lowerBounds != null) {
+            return OBJECT;
+        }
+        if (upperBounds != null) {
+            return upperBounds.getRawType();
+        }
+        TypeMetaData rawType = new TypeMetaData(name);
+        rawType.arrayDimensions = arrayDimensions;
+        rawType.varargs = varargs;
+        return rawType;
+    }
+
+    public String getSignature() {
+        final StringBuilder builder = new StringBuilder();
+
+        visitSignature(new SignatureVisitor() {
+            public void visitText(String text) {
+                builder.append(text);
+            }
+
+            public void visitType(String name) {
+                builder.append(name);
+            }
+        });
+        return builder.toString();
+    }
+
+    public String getArraySuffix() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < arrayDimensions; i++) {
+            builder.append("[]");
+        }
+        if (varargs) {
+            builder.append("...");
+        }
+        return builder.toString();
+    }
+
+    public TypeMetaData addTypeArg(TypeMetaData typeArg) {
+        if (typeArgs == null) {
+            typeArgs = new ArrayList<TypeMetaData>();
+        }
+        typeArgs.add(typeArg);
+        return this;
+    }
+
+    public void visitTypes(Action<TypeMetaData> action) {
+        if (wildcard) {
+            return;
+        }
+        if (upperBounds != null) {
+            upperBounds.visitTypes(action);
+            return;
+        }
+        if (lowerBounds != null) {
+            lowerBounds.visitTypes(action);
+            return;
+        }
+        
+        action.execute(this);
+        if (typeArgs != null) {
+            for (TypeMetaData typeArg : typeArgs) {
+                typeArg.visitTypes(action);
+            }
+        }
+    }
+
+    public void visitSignature(SignatureVisitor visitor) {
+        if (wildcard) {
+            visitor.visitText("?");
+        } else if (upperBounds != null) {
+            visitor.visitText("? extends ");
+            upperBounds.visitSignature(visitor);
+        } else if (lowerBounds != null) {
+            visitor.visitText("? super ");
+            lowerBounds.visitSignature(visitor);
+        } else {
+            visitor.visitType(name);
+            if (typeArgs != null) {
+                visitor.visitText("<");
+                for (int i = 0; i < typeArgs.size(); i++) {
+                    if (i > 0) {
+                        visitor.visitText(", ");
+                    }
+                    TypeMetaData typeArg = typeArgs.get(i);
+                    typeArg.visitSignature(visitor);
+                }
+                visitor.visitText(">");
+            }
+            String suffix = getArraySuffix();
+            if (suffix.length() > 0) {
+                visitor.visitText(suffix);
+            }
+        }
+    }
+
+    public TypeMetaData setWildcard() {
+        wildcard = true;
+        return this;
+    }
+
+    public TypeMetaData setUpperBounds(TypeMetaData upperBounds) {
+        this.upperBounds = upperBounds;
+        return this;
+    }
+
+    public TypeMetaData setLowerBounds(TypeMetaData lowerBounds) {
+        this.lowerBounds = lowerBounds;
+        return this;
+    }
+
+    public interface SignatureVisitor {
+        void visitText(String text);
+
+        void visitType(String name);
+    }
+}
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/model/Attachable.java
similarity index 58%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/model/Attachable.java
index 2a4f998..3e6f820 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/model/Attachable.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.model;
 
-import org.gradle.api.Project
-
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
-
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
-
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+public interface Attachable<T> {
+    void attach(ClassMetaDataRepository<T> repository);
+}
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/model/ClassMetaDataRepository.java
similarity index 57%
copy from subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
copy to buildSrc/src/main/groovy/org/gradle/build/docs/model/ClassMetaDataRepository.java
index 2a4f998..8683d0a 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/model/ClassMetaDataRepository.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -13,20 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.api.plugins
+package org.gradle.build.docs.model;
 
-import org.gradle.api.Project
+import groovy.lang.Closure;
+import org.gradle.api.UnknownDomainObjectException;
 
-public class WarPluginConvention {
-    String webAppDirName
-    final Project project
+public interface ClassMetaDataRepository<T> {
+    T get(String fullyQualifiedClassName) throws UnknownDomainObjectException;
 
-    def WarPluginConvention(Project project) {
-        this.project = project
-        webAppDirName = 'src/main/webapp'
-    }
+    T find(String fullyQualifiedClassName);
 
-    File getWebAppDir() {
-        project.file(webAppDirName)
-    }
-}
\ No newline at end of file
+    void put(String fullyQualifiedClassName, T metaData);
+
+    void each(Closure cl);
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepository.java b/buildSrc/src/main/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepository.java
new file mode 100644
index 0000000..43d8936
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepository.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.model;
+
+import groovy.lang.Closure;
+import org.gradle.api.GradleException;
+import org.gradle.api.UnknownDomainObjectException;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SimpleClassMetaDataRepository<T extends Attachable<T>> implements ClassMetaDataRepository<T> {
+    private final Map<String, T> classes = new HashMap<String, T>();
+
+    public void load(File repoFile) {
+        try {
+            FileInputStream inputStream = new FileInputStream(repoFile);
+            try {
+                ObjectInputStream objInputStream = new ObjectInputStream(new BufferedInputStream(inputStream));
+                classes.clear();
+                classes.putAll((Map<String, T>) objInputStream.readObject());
+            } finally {
+                inputStream.close();
+            }
+        } catch (Exception e) {
+            throw new GradleException(String.format("Could not load meta-data from %s.", repoFile), e);
+        }
+    }
+
+    public void store(File repoFile) {
+        try {
+            FileOutputStream outputStream = new FileOutputStream(repoFile);
+            try {
+                ObjectOutputStream objOutputStream = new ObjectOutputStream(new BufferedOutputStream(outputStream));
+                objOutputStream.writeObject(classes);
+                objOutputStream.close();
+            } finally {
+                outputStream.close();
+            }
+        } catch (IOException e) {
+            throw new GradleException(String.format("Could not write meta-data to %s.", repoFile), e);
+        }
+    }
+
+    public T get(String fullyQualifiedClassName) {
+        T t = find(fullyQualifiedClassName);
+        if (t == null) {
+            throw new UnknownDomainObjectException(String.format("No meta-data is available for class '%s'.", fullyQualifiedClassName));
+        }
+        return t;
+    }
+
+    public T find(String fullyQualifiedClassName) {
+        T t = classes.get(fullyQualifiedClassName);
+        if (t != null) {
+            t.attach(this);
+        }
+        return t;
+    }
+
+    public void put(String fullyQualifiedClassName, T metaData) {
+        classes.put(fullyQualifiedClassName, metaData);
+    }
+
+    public void each(Closure cl) {
+        for (Map.Entry<String, T> entry : classes.entrySet()) {
+            cl.call(new Object[]{entry.getKey(), entry.getValue()});
+        }
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTaskTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTaskTest.groovy
new file mode 100644
index 0000000..c76e513
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/ExtractDslMetaDataTaskTest.groovy
@@ -0,0 +1,641 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl
+
+import org.gradle.api.Project
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.model.SimpleClassMetaDataRepository
+import org.gradle.testfixtures.ProjectBuilder
+import spock.lang.Specification
+
+class ExtractDslMetaDataTaskTest extends Specification {
+    final Project project = new ProjectBuilder().build()
+    final ExtractDslMetaDataTask task = project.tasks.add('dsl', ExtractDslMetaDataTask.class)
+    final SimpleClassMetaDataRepository<ClassMetaData> repository = new SimpleClassMetaDataRepository<ClassMetaData>()
+
+    def setup() {
+        task.destFile = project.file('meta-data.bin')
+    }
+
+    def extractsClassMetaDataFromGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClass.groovy')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/A.groovy')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+        task.source testFile('org/gradle/test/Interface1.java')
+        task.source testFile('org/gradle/test/Interface2.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClass')
+        metaData.groovy
+        !metaData.isInterface()
+        metaData.rawCommentText.contains('This is a groovy class.')
+        metaData.superClassName == 'org.gradle.test.A'
+        metaData.interfaceNames == ['org.gradle.test.GroovyInterface', 'org.gradle.test.JavaInterface']
+
+        metaData = repository.get('org.gradle.test.GroovyInterface')
+        metaData.groovy
+        metaData.isInterface()
+        metaData.superClassName == null
+        metaData.interfaceNames == ['org.gradle.test.Interface1', 'org.gradle.test.Interface2']
+    }
+
+    def extractsClassMetaDataFromJavaSource() {
+        task.source testFile('org/gradle/test/JavaClass.java')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+        task.source testFile('org/gradle/test/A.groovy')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/Interface1.java')
+        task.source testFile('org/gradle/test/Interface2.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClass')
+        !metaData.groovy
+        !metaData.isInterface()
+        metaData.rawCommentText.contains('This is a java class.')
+        metaData.superClassName == 'org.gradle.test.A'
+        metaData.interfaceNames == ['org.gradle.test.GroovyInterface', 'org.gradle.test.JavaInterface']
+
+        metaData = repository.get('org.gradle.test.JavaInterface')
+        !metaData.groovy
+        metaData.isInterface()
+        metaData.superClassName == null
+        metaData.interfaceNames == ['org.gradle.test.Interface1', 'org.gradle.test.Interface2']
+    }
+
+    def extractsPropertyMetaDataFromGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClass.groovy')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClass')
+        metaData.declaredPropertyNames == ['readOnly', 'writeOnly', 'someProp', 'groovyProp', 'readOnlyGroovyProp', 'arrayProp'] as Set
+
+        def prop = metaData.findDeclaredProperty('readOnly')
+        prop.type.signature == 'java.lang.Object'
+        prop.rawCommentText.contains('A read-only property.')
+        !prop.writeable
+        prop.getter.rawCommentText.contains('A read-only property.')
+        !prop.setter
+
+        prop = metaData.findDeclaredProperty('writeOnly')
+        prop.type.signature == 'org.gradle.test.JavaInterface'
+        prop.rawCommentText.contains('A write-only property.')
+        prop.writeable
+        !prop.getter
+        prop.setter.rawCommentText.contains('A write-only property.')
+
+        prop = metaData.findDeclaredProperty('someProp')
+        prop.type.signature == 'org.gradle.test.GroovyInterface'
+        prop.rawCommentText.contains('A property.')
+        prop.writeable
+        prop.getter.rawCommentText.contains('A property.')
+        prop.setter.rawCommentText == ''
+
+        prop = metaData.findDeclaredProperty('groovyProp')
+        prop.type.signature == 'org.gradle.test.GroovyInterface'
+        prop.rawCommentText.contains('A groovy property.')
+        prop.writeable
+        prop.getter.rawCommentText == ''
+        prop.setter.rawCommentText == ''
+
+        prop = metaData.findDeclaredProperty('readOnlyGroovyProp')
+        prop.type.signature == 'java.lang.String'
+        prop.rawCommentText.contains('A read-only groovy property.')
+        !prop.writeable
+        prop.getter.rawCommentText == ''
+        !prop.setter
+
+        prop = metaData.findDeclaredProperty('arrayProp')
+        prop.type.signature == 'java.lang.String[]'
+        prop.rawCommentText.contains('An array property.')
+        prop.writeable
+        prop.getter.rawCommentText == ''
+        prop.setter.rawCommentText == ''
+    }
+
+    def extractsPropertyMetaDataFromJavaSource() {
+        task.source testFile('org/gradle/test/JavaClass.java')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClass')
+        metaData.declaredPropertyNames == ['readOnly', 'writeOnly', 'someProp', 'flag', 'arrayProp'] as Set
+
+        def prop = metaData.findDeclaredProperty('readOnly')
+        prop.type.signature == 'java.lang.String'
+        prop.rawCommentText.contains('A read-only property.')
+        !prop.writeable
+        prop.getter.rawCommentText.contains('A read-only property.')
+        !prop.setter
+
+        prop = metaData.findDeclaredProperty('writeOnly')
+        prop.type.signature == 'org.gradle.test.JavaInterface'
+        prop.rawCommentText.contains('A write-only property.')
+        prop.writeable
+        !prop.getter
+        prop.setter.rawCommentText.contains('A write-only property.')
+
+        prop = metaData.findDeclaredProperty('someProp')
+        prop.type.signature == 'org.gradle.test.JavaInterface'
+        prop.rawCommentText.contains('A property.')
+        prop.writeable
+        prop.getter.rawCommentText.contains('A property.')
+        prop.setter.rawCommentText.contains('The setter for a property.')
+
+        prop = metaData.findDeclaredProperty('flag')
+        prop.type.signature == 'boolean'
+        prop.rawCommentText.contains('A boolean property.')
+        !prop.writeable
+        prop.getter.rawCommentText.contains('A boolean property.')
+        !prop.setter
+
+        prop = metaData.findDeclaredProperty('arrayProp')
+        prop.type.signature == 'org.gradle.test.JavaInterface[][][]'
+        prop.rawCommentText.contains('An array property.')
+        !prop.writeable
+        prop.getter.rawCommentText.contains('An array property.')
+        !prop.setter
+    }
+
+    def extractsMethodMetaDataFromGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithMethods.groovy')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithMethods')
+        metaData.declaredMethods.collect { it.name } as Set == ['stringMethod', 'refTypeMethod', 'defMethod', 'voidMethod', 'arrayMethod', 'setProp', 'getProp', 'getFinalProp', 'getIntProp', 'setIntProp'] as Set
+
+        def method = metaData.declaredMethods.find { it.name == 'stringMethod' }
+        method.rawCommentText.contains('A method that returns String')
+        method.returnType.signature == 'java.lang.String'
+        method.parameters.collect { it.name } == ['stringParam']
+
+        def param = method.parameters[0]
+        param.name == 'stringParam'
+        param.type.signature == 'java.lang.String'
+
+        method = metaData.declaredMethods.find { it.name == 'refTypeMethod' }
+        method.rawCommentText.contains('A method that returns a reference type.')
+        method.returnType.signature == 'org.gradle.test.GroovyInterface'
+        method.parameters.collect { it.name } == ['someThing', 'aFlag']
+
+        param = method.parameters[0]
+        param.name == 'someThing'
+        param.type.signature == 'org.gradle.test.JavaInterface'
+
+        param = method.parameters[1]
+        param.name == 'aFlag'
+        param.type.signature == 'boolean'
+
+        method = metaData.declaredMethods.find { it.name == 'defMethod' }
+        method.rawCommentText.contains('A method that returns a default type.')
+        method.returnType.signature == 'java.lang.Object'
+        method.parameters.collect { it.name } == ['defParam']
+
+        param = method.parameters[0]
+        param.name == 'defParam'
+        param.type.signature == 'java.lang.Object'
+
+        method = metaData.declaredMethods.find { it.name == 'voidMethod' }
+        method.rawCommentText.contains('A method that returns void.')
+        method.returnType.signature == 'void'
+        method.parameters.collect { it.name } == []
+
+        method = metaData.declaredMethods.find { it.name == 'arrayMethod' }
+        method.returnType.signature == 'java.lang.String[][]'
+        method.returnType.arrayDimensions == 2
+        method.parameters.collect { it.name } == ['strings']
+
+        param = method.parameters[0]
+        param.name == 'strings'
+        param.type.signature == 'java.lang.String[]...'
+        param.type.arrayDimensions == 2
+
+        method = metaData.declaredMethods.find { it.name == 'getProp' }
+        method.rawCommentText == ''
+        method.returnType.signature == 'java.lang.String'
+        method.parameters.collect { it.name } == []
+
+        method = metaData.declaredMethods.find { it.name == 'setProp' }
+        method.rawCommentText == ''
+        method.returnType.signature == 'void'
+        method.parameters.collect { it.name } == ['prop']
+
+        param = method.parameters[0]
+        param.name == 'prop'
+        param.type.signature == 'java.lang.String'
+
+        method = metaData.declaredMethods.find { it.name == 'getFinalProp' }
+        method.rawCommentText == ''
+        method.returnType.signature == 'org.gradle.test.JavaInterface'
+        method.parameters.collect { it.name } == []
+
+        metaData.declaredPropertyNames == ['prop', 'finalProp', 'intProp'] as Set
+    }
+
+    def extractsMethodMetaDataFromJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithMethods.java')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithMethods')
+        metaData.declaredMethods.collect { it.name } as Set == ['stringMethod', 'refTypeMethod', 'voidMethod', 'arrayMethod', 'getIntProp', 'setIntProp'] as Set
+
+        def method = metaData.declaredMethods.find { it.name == 'stringMethod' }
+        method.rawCommentText.contains('A method that returns String')
+        method.returnType.signature == 'java.lang.String'
+        method.parameters.collect { it.name } == ['stringParam']
+
+        def param = method.parameters[0]
+        param.name == 'stringParam'
+        param.type.signature == 'java.lang.String'
+
+        method = metaData.declaredMethods.find { it.name == 'refTypeMethod' }
+        method.rawCommentText.contains('A method that returns a reference type.')
+        method.returnType.signature == 'org.gradle.test.GroovyInterface'
+        method.parameters.collect { it.name } == ['refParam', 'aFlag']
+
+        param = method.parameters[0]
+        param.name == 'refParam'
+        param.type.signature == 'org.gradle.test.JavaInterface'
+
+        param = method.parameters[1]
+        param.name == 'aFlag'
+        param.type.signature == 'boolean'
+
+        method = metaData.declaredMethods.find { it.name == 'voidMethod' }
+        method.rawCommentText.contains('A method that returns void.')
+        method.returnType.signature == 'void'
+        method.parameters.collect { it.name } == []
+
+        method = metaData.declaredMethods.find { it.name == 'arrayMethod' }
+        method.returnType.signature == 'java.lang.String[][]'
+        method.returnType.arrayDimensions == 2
+        method.parameters.collect { it.name } == ['strings']
+
+        param = method.parameters[0]
+        param.name == 'strings'
+        param.type.signature == 'java.lang.String[]...'
+        param.type.arrayDimensions == 2
+
+        metaData.declaredPropertyNames == ['intProp'] as Set
+    }
+
+    def extractsConstantsFromGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithConstants.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithConstants')
+        metaData.constants.keySet() == ['INT_CONST', 'STRING_CONST', 'OBJECT_CONST', 'BIG_DECIMAL_CONST'] as Set
+
+        metaData.constants['INT_CONST'] == '9'
+        metaData.constants['STRING_CONST'] == 'some-string'
+        metaData.constants['BIG_DECIMAL_CONST'] == '1.02'
+        metaData.constants['OBJECT_CONST'] == null
+    }
+
+    def extractsConstantsFromJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithConstants.java')
+        task.source testFile('org/gradle/test/JavaInterfaceWithConstants.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithConstants')
+        metaData.constants.keySet() == ['INT_CONST', 'STRING_CONST', 'OBJECT_CONST', 'CHAR_CONST'] as Set
+
+        metaData.constants['INT_CONST'] == '9'
+        metaData.constants['STRING_CONST'] == 'some-string'
+        metaData.constants['CHAR_CONST'] == 'a'
+        metaData.constants['OBJECT_CONST'] == null
+
+        metaData = repository.get('org.gradle.test.JavaInterfaceWithConstants')
+        metaData.constants.keySet() == ['INT_CONST', 'STRING_CONST'] as Set
+
+        metaData.constants['INT_CONST'] == '120'
+        metaData.constants['STRING_CONST'] == 'some-string'
+    }
+
+    def handlesFullyQualifiedNamesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithFullyQualifiedNames.groovy')
+        task.source testFile('org/gradle/test/sub/SubJavaInterface.java')
+        task.source testFile('org/gradle/test/sub/SubGroovyClass.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithFullyQualifiedNames')
+        metaData.superClassName == 'org.gradle.test.sub.SubGroovyClass'
+        metaData.interfaceNames == ['org.gradle.test.sub.SubJavaInterface', 'java.lang.Runnable']
+        metaData.declaredPropertyNames == ['prop'] as Set
+
+        def prop = metaData.findDeclaredProperty('prop')
+        prop.type.signature == 'org.gradle.test.sub.SubJavaInterface'
+    }
+
+    def handlesFullyQualifiedNamesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithFullyQualifiedNames.java')
+        task.source testFile('org/gradle/test/sub/SubJavaInterface.java')
+        task.source testFile('org/gradle/test/sub/SubGroovyClass.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithFullyQualifiedNames')
+        metaData.superClassName == 'org.gradle.test.sub.SubGroovyClass'
+        metaData.interfaceNames == ['org.gradle.test.sub.SubJavaInterface', 'java.lang.Runnable']
+        metaData.declaredPropertyNames == ['prop'] as Set
+
+        def prop = metaData.findDeclaredProperty('prop')
+        prop.type.signature == 'org.gradle.test.sub.SubJavaInterface'
+    }
+
+    def handlesImportedTypesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithImports.groovy')
+        task.source testFile('org/gradle/test/sub/SubJavaInterface.java')
+        task.source testFile('org/gradle/test/sub/SubGroovyClass.groovy')
+        task.source testFile('org/gradle/test/sub2/GroovyInterface.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithImports')
+        metaData.superClassName == 'org.gradle.test.sub.SubGroovyClass'
+        metaData.interfaceNames == ['org.gradle.test.sub.SubJavaInterface', 'org.gradle.test.sub2.GroovyInterface']
+        metaData.declaredPropertyNames == [] as Set
+    }
+
+    def handlesImportedTypesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithImports.java')
+        task.source testFile('org/gradle/test/sub/SubJavaInterface.java')
+        task.source testFile('org/gradle/test/sub/SubGroovyClass.groovy')
+        task.source testFile('org/gradle/test/sub2/GroovyInterface.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithImports')
+        metaData.superClassName == 'org.gradle.test.sub.SubGroovyClass'
+        metaData.interfaceNames == ['org.gradle.test.sub.SubJavaInterface', 'org.gradle.test.sub2.GroovyInterface', 'java.io.Closeable']
+        metaData.declaredPropertyNames == [] as Set
+    }
+
+    def handlesEnumTypesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyEnum.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyEnum')
+        metaData.groovy
+        !metaData.isInterface()
+    }
+
+    def handlesEnumTypesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaEnum.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaEnum')
+        !metaData.groovy
+        !metaData.isInterface()
+    }
+
+    def handlesAnnotationTypesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyAnnotation.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyAnnotation')
+        metaData.groovy
+        !metaData.isInterface()
+    }
+
+    def handlesAnnotationTypesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaAnnotation.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaAnnotation')
+        !metaData.groovy
+        !metaData.isInterface()
+    }
+
+    def handlesNestedAndAnonymousTypesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithInnerTypes.groovy')
+        task.source testFile('org/gradle/test/sub2/GroovyInterface.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithInnerTypes')
+        metaData.interfaceNames == ['org.gradle.test.sub2.GroovyInterface']
+        metaData.declaredPropertyNames == ['someProp', 'innerClassProp'] as Set
+
+        def propMetaData = metaData.findDeclaredProperty('someProp')
+        propMetaData.type.signature == 'org.gradle.test.sub2.GroovyInterface'
+
+        propMetaData = metaData.findDeclaredProperty('innerClassProp')
+        propMetaData.type.signature == 'org.gradle.test.GroovyClassWithInnerTypes.InnerClass.AnotherInner'
+
+        metaData = repository.get('org.gradle.test.GroovyClassWithInnerTypes.InnerEnum')
+        metaData.rawCommentText.contains('This is an inner enum.')
+
+        metaData = repository.get('org.gradle.test.GroovyClassWithInnerTypes.InnerClass')
+        metaData.rawCommentText.contains('This is an inner class.')
+        metaData.declaredPropertyNames == ['enumProp'] as Set
+
+        propMetaData = metaData.findDeclaredProperty('enumProp')
+        propMetaData.type.signature == 'org.gradle.test.GroovyClassWithInnerTypes.InnerEnum'
+
+        metaData = repository.get('org.gradle.test.GroovyClassWithInnerTypes.InnerClass.AnotherInner')
+        metaData.rawCommentText.contains('This is an inner inner class.')
+        metaData.declaredPropertyNames == ['outer'] as Set
+
+        propMetaData = metaData.findDeclaredProperty('outer')
+        propMetaData.type.signature == 'org.gradle.test.GroovyClassWithInnerTypes.InnerClass'
+    }
+
+    def handlesNestedAndAnonymousTypesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithInnerTypes.java')
+        task.source testFile('org/gradle/test/sub2/GroovyInterface.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithInnerTypes')
+        metaData.interfaceNames == ['org.gradle.test.sub2.GroovyInterface']
+        metaData.declaredPropertyNames == ['someProp', 'innerClassProp'] as Set
+
+        def propMetaData = metaData.findDeclaredProperty('someProp')
+        propMetaData.type.signature == 'org.gradle.test.sub2.GroovyInterface'
+
+        propMetaData = metaData.findDeclaredProperty('innerClassProp')
+        propMetaData.type.signature == 'org.gradle.test.JavaClassWithInnerTypes.InnerClass.AnotherInner'
+
+        metaData = repository.get('org.gradle.test.JavaClassWithInnerTypes.InnerEnum')
+        metaData.rawCommentText.contains('This is an inner enum.')
+
+        metaData = repository.get('org.gradle.test.JavaClassWithInnerTypes.InnerClass')
+        metaData.rawCommentText.contains('This is an inner class.')
+        metaData.declaredPropertyNames == ['enumProp'] as Set
+
+        propMetaData = metaData.findDeclaredProperty('enumProp')
+        propMetaData.type.signature == 'org.gradle.test.JavaClassWithInnerTypes.InnerEnum'
+
+        metaData = repository.get('org.gradle.test.JavaClassWithInnerTypes.InnerClass.AnotherInner')
+        metaData.rawCommentText.contains('This is an inner inner class.')
+        metaData.declaredPropertyNames == ['outer'] as Set
+
+        propMetaData = metaData.findDeclaredProperty('outer')
+        propMetaData.type.signature == 'org.gradle.test.JavaClassWithInnerTypes.InnerClass'
+    }
+
+    def handlesParameterizedTypesInGroovySource() {
+        task.source testFile('org/gradle/test/GroovyClassWithParameterizedTypes.groovy')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.GroovyClassWithParameterizedTypes')
+
+        def property = metaData.findDeclaredProperty('setProp')
+        property.type.signature == 'java.util.Set<org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('mapProp')
+        property.type.signature == 'java.util.Map<org.gradle.test.GroovyInterface, org.gradle.test.GroovyClassWithParameterizedTypes>'
+
+        property = metaData.findDeclaredProperty('wildcardProp')
+        property.type.signature == 'java.util.List<?>'
+
+        property = metaData.findDeclaredProperty('upperBoundProp')
+        property.type.signature == 'java.util.List<? extends org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('lowerBoundProp')
+        property.type.signature == 'java.util.List<? super org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('nestedProp')
+        property.type.signature == 'java.util.List<? super java.util.Set<? extends java.util.Map<?, org.gradle.test.GroovyInterface[]>>>[]'
+
+        def method = metaData.declaredMethods.find { it.name == 'paramMethod' }
+        method.returnType.signature == 'T'
+        method.parameters[0].type.signature == 'T'
+    }
+
+    def handlesParameterizedTypesInJavaSource() {
+        task.source testFile('org/gradle/test/JavaClassWithParameterizedTypes.java')
+        task.source testFile('org/gradle/test/GroovyInterface.groovy')
+        task.source testFile('org/gradle/test/JavaInterface.java')
+
+        when:
+        task.extract()
+        repository.load(task.destFile)
+
+        then:
+        def metaData = repository.get('org.gradle.test.JavaClassWithParameterizedTypes')
+
+        def property = metaData.findDeclaredProperty('setProp')
+        property.type.signature == 'java.util.Set<org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('mapProp')
+        property.type.signature == 'java.util.Map<org.gradle.test.GroovyInterface, org.gradle.test.JavaClassWithParameterizedTypes>'
+
+        property = metaData.findDeclaredProperty('wildcardProp')
+        property.type.signature == 'java.util.List<?>'
+
+        property = metaData.findDeclaredProperty('upperBoundProp')
+        property.type.signature == 'java.util.List<? extends org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('lowerBoundProp')
+        property.type.signature == 'java.util.List<? super org.gradle.test.GroovyInterface>'
+
+        property = metaData.findDeclaredProperty('nestedProp')
+        property.type.signature == 'java.util.List<? super java.util.Set<? extends java.util.Map<?, org.gradle.test.GroovyInterface[]>>>[]'
+
+        def method = metaData.declaredMethods.find { it.name == 'paramMethod' }
+        method.returnType.signature == 'T'
+
+        def param = method.parameters[0]
+        param.type.signature == 'T'
+    }
+
+    def testFile(String fileName) {
+        URL resource = getClass().classLoader.getResource(fileName)
+        assert resource != null
+        assert resource.protocol == 'file'
+        return new File(resource.path)
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/TypeNameResolverTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/TypeNameResolverTest.groovy
new file mode 100644
index 0000000..caf1bdf
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/TypeNameResolverTest.groovy
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl
+
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import spock.lang.Specification
+import org.gradle.build.docs.dsl.model.TypeMetaData
+
+class TypeNameResolverTest extends Specification {
+    final ClassMetaDataRepository<ClassMetaData> metaDataRepository = Mock()
+    final ClassMetaData classMetaData = Mock()
+    final TypeNameResolver typeNameResolver = new TypeNameResolver(metaDataRepository)
+
+    def resolvesFullyQualifiedClassName() {
+        when:
+        def name = typeNameResolver.resolve('org.gradle.SomeClass', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass'
+        _ * classMetaData.innerClassNames >> []
+    }
+
+    def resolvesUnqualifiedNameToClassInSamePackage() {
+        when:
+        def name = typeNameResolver.resolve('SomeClass', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> []
+        _ * classMetaData.packageName >> 'org.gradle'
+        _ * metaDataRepository.find('org.gradle.SomeClass') >> classMetaData
+    }
+
+    def resolvesUnqualifiedNameToImportedClass() {
+        when:
+        def name = typeNameResolver.resolve('SomeClass', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> ['org.gradle.SomeClass']
+    }
+
+    def resolvesUnqualifiedNameToImportedPackage() {
+        when:
+        def name = typeNameResolver.resolve('SomeClass', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> ['org.gradle.*']
+        _ * metaDataRepository.find('org.gradle.SomeClass') >> classMetaData
+    }
+
+    def resolvesUnqualifiedNameToInnerClass() {
+        when:
+        def name = typeNameResolver.resolve('Inner', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass.Inner'
+        _ * classMetaData.innerClassNames >> ['org.gradle.SomeClass.Inner']
+        _ * classMetaData.className >> 'org.gradle.SomeClass'
+    }
+
+    def resolvesQualifiedNameToInnerClass() {
+        ClassMetaData innerClass = Mock()
+
+        when:
+        def name = typeNameResolver.resolve('A.B', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass.A.B'
+        _ * classMetaData.innerClassNames >> ['org.gradle.SomeClass.A']
+        _ * classMetaData.className >> 'org.gradle.SomeClass'
+        _ * metaDataRepository.get('org.gradle.SomeClass.A') >> innerClass
+        _ * innerClass.innerClassNames >> ['org.gradle.SomeClass.A.B']
+        _ * innerClass.className >> 'org.gradle.SomeClass.A'
+    }
+
+    def resolvesUnqualifiedNameToOuterClass() {
+        when:
+        def name = typeNameResolver.resolve('Outer', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass.Outer'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.outerClassName >> 'org.gradle.SomeClass.Outer'
+    }
+
+    def resolvesUnqualifiedNameToSiblingClass() {
+        ClassMetaData outerClass = Mock()
+
+        when:
+        def name = typeNameResolver.resolve('Sibling', classMetaData)
+
+        then:
+        name == 'org.gradle.SomeClass.Outer.Sibling'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.outerClassName >> 'org.gradle.SomeClass.Outer'
+        _ * metaDataRepository.get('org.gradle.SomeClass.Outer') >> outerClass
+        _ * outerClass.innerClassNames >> ['org.gradle.SomeClass.Outer.Sibling']
+    }
+
+    def resolvesUnqualifiedNameToJavaLangPackage() {
+        when:
+        def name = typeNameResolver.resolve('String', classMetaData)
+
+        then:
+        name == 'java.lang.String'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> []
+    }
+
+    def resolvesUnqualifiedNameToDefaultPackagesAndClassesInGroovySource() {
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> []
+        _ * classMetaData.groovy >> true
+
+        expect:
+        typeNameResolver.resolve('Set', classMetaData) == 'java.util.Set'
+        typeNameResolver.resolve('File', classMetaData) == 'java.io.File'
+        typeNameResolver.resolve('Closure', classMetaData) == 'groovy.lang.Closure'
+        typeNameResolver.resolve('BigDecimal', classMetaData) == 'java.math.BigDecimal'
+        typeNameResolver.resolve('BigInteger', classMetaData) == 'java.math.BigInteger'
+    }
+
+    def resolvesUnqualifiedNameToImportedJavaPackage() {
+        when:
+        def name = typeNameResolver.resolve('Set', classMetaData)
+
+        then:
+        name == 'java.util.Set'
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> ['java.util.*']
+    }
+
+    def resolvesPrimitiveType() {
+        when:
+        def name = typeNameResolver.resolve('boolean', classMetaData)
+
+        then:
+        name == 'boolean'
+    }
+
+    def resolvesParameterisedTypes() {
+        def typeMetaData = type('SomeClass')
+        typeMetaData.addTypeArg(type('String'))
+
+        when:
+        typeNameResolver.resolve(typeMetaData, classMetaData)
+
+        then:
+        typeMetaData.signature == 'org.gradle.SomeClass<java.lang.String>'
+
+        _ * classMetaData.innerClassNames >> []
+        _ * classMetaData.imports >> ['org.gradle.SomeClass']
+    }
+
+    def type(String name) {
+        return new TypeMetaData(name)
+    }
+}
+
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy
new file mode 100644
index 0000000..38dae26
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl
+
+import spock.lang.Specification
+import org.w3c.dom.Document
+import javax.xml.parsers.DocumentBuilderFactory
+import org.w3c.dom.Node
+import org.w3c.dom.Element
+import org.w3c.dom.Text
+import org.w3c.dom.Attr
+import javax.xml.parsers.DocumentBuilder
+import org.xml.sax.InputSource
+import org.gradle.build.docs.BuildableDOMCategory
+import groovy.xml.dom.DOMCategory
+
+class XmlSpecification extends Specification {
+    final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
+
+    def parse(String str) {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()
+        factory.setNamespaceAware(true)
+        DocumentBuilder builder = factory.newDocumentBuilder()
+        return builder.parse(new InputSource(new StringReader(str))).documentElement
+    }
+
+    def formatTree(Closure cl) {
+        withCategories {
+            return formatTree(cl.call())
+        }
+    }
+
+    def withCategories(Closure cl) {
+        use(DOMCategory) {
+            use(BuildableDOMCategory) {
+                return cl.call()
+            }
+        }
+    }
+
+    def format(Node... nodes) {
+        format(nodes as List)
+    }
+
+    def formatTree(Node... nodes) {
+        formatTree(nodes as List)
+    }
+
+    def formatTree(Iterable<? extends Node> nodes) {
+        format(nodes, true)
+    }
+
+    def format(Iterable<? extends Node> nodes, boolean prettyPrint = false) {
+        StringBuilder builder = new StringBuilder()
+        nodes.each { node ->
+            format(node, builder, 0, prettyPrint, prettyPrint)
+        }
+        return builder.toString()
+    }
+
+    def format(Node node, Appendable target, int depth, boolean prettyPrint, boolean indentSelf) {
+        if (node instanceof Element) {
+            Element element = (Element) node
+
+            if (indentSelf && depth > 0) {
+                target.append('\n')
+                depth.times { target.append('    ') }
+            }
+
+            target.append("<${element.tagName}")
+            for (int i = 0; i < element.attributes.length; i++) {
+                Attr attr = element.attributes.item(i)
+                target.append(" $attr.name=\"$attr.value\"")
+            }
+
+            List<Node> trimmedContent = element.childNodes.collect { it };
+            boolean inlineContent = trimmedContent.find { it instanceof Text && it.textContent.trim() }
+
+            if (prettyPrint && !inlineContent) {
+                trimmedContent = element.childNodes.inject([]) { list, child ->
+                    if (!(child instanceof Text) || child.textContent.trim().length() != 0) {
+                        list << child
+                    }
+                    return list
+                }
+            }
+
+            if (trimmedContent.isEmpty()) {
+                target.append('/>')
+                return
+            }
+            target.append('>')
+
+
+            trimmedContent.each { child ->
+                format(child, target, depth + 1, prettyPrint, prettyPrint && !inlineContent)
+            }
+
+            if (prettyPrint && indentSelf && !inlineContent) {
+                target.append('\n')
+                depth.times { target.append('    ') }
+            }
+
+            target.append("</${element.tagName}>")
+
+            return
+        }
+
+        if (node instanceof Text) {
+            target.append(node.nodeValue.replace('&', '&').replace('<', '<').replace('>', '>'))
+            return
+        }
+        
+        throw new UnsupportedOperationException("Don't know how to format DOM node: $node")
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexerTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexerTest.groovy
new file mode 100644
index 0000000..9437165
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/BasicJavadocLexerTest.groovy
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import spock.lang.Specification
+
+class BasicJavadocLexerTest extends Specification {
+    final BasicJavadocLexer lexer = new BasicJavadocLexer(new JavadocScanner(""))
+    final JavadocLexer.TokenVisitor visitor = Mock()
+
+    def parsesHtmlElements() {
+        when:
+        lexer.pushText("<p> text </p>")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartHtmlElement('p')
+        1 * visitor.onStartHtmlElementComplete('p')
+        1 * visitor.onText(' text ')
+        1 * visitor.onEndHtmlElement('p')
+        0 * visitor._
+    }
+
+    def normalizesHtmlElementNamesToLowercase() {
+        when:
+        lexer.pushText("<P></End>")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartHtmlElement('p')
+        1 * visitor.onStartHtmlElementComplete('p')
+        1 * visitor.onEndHtmlElement('end')
+        0 * visitor._
+    }
+
+    def parsesHtmlEntities() {
+        when:
+        lexer.pushText("before & after")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onText('before & after')
+        0 * visitor._
+    }
+
+    def parsesStartHtmlElementWithAttributes() {
+        when:
+        lexer.pushText("<a name='value' other='\n& '\n \"'>")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartHtmlElement('a')
+        1 * visitor.onHtmlElementAttribute('name', 'value')
+        1 * visitor.onHtmlElementAttribute('other', '\n& \'\n \"')
+        1 * visitor.onStartHtmlElementComplete('a')
+        0 * visitor._
+    }
+
+    def canUseSingleOrDoubleQuotesForAttributeValues() {
+        when:
+        lexer.pushText("<a single='a=\"b\"' double = \"a='b'\">")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartHtmlElement('a')
+        1 * visitor.onHtmlElementAttribute('single', 'a=\"b\"')
+        1 * visitor.onHtmlElementAttribute('double', 'a=\'b\'')
+        1 * visitor.onStartHtmlElementComplete('a')
+        0 * visitor._
+    }
+
+    def splitsHtmlElementWithNoContentIntoSeparateStartAndEndTokens() {
+        when:
+        lexer.pushText("<p/>")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartHtmlElement('p')
+        1 * visitor.onStartHtmlElementComplete('p')
+        1 * visitor.onEndHtmlElement('p')
+        0 * visitor._
+    }
+
+    def parsesJavadocTags() {
+        when:
+        lexer.pushText("{@tag some value}")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartJavadocTag('tag')
+        1 * visitor.onText('some value')
+        1 * visitor.onEndJavadocTag('tag')
+        0 * visitor._
+    }
+
+    def javadocTagCanBeEmpty() {
+        when:
+        lexer.pushText("{@empty}")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartJavadocTag('empty')
+        1 * visitor.onEndJavadocTag('empty')
+        0 * visitor._
+    }
+
+    def ignoresWhitespaceAndEOLCharsBetweenJavadocTagNameAndValue() {
+        when:
+        lexer.pushText("* {@link\n *  Something}")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartJavadocTag('link')
+        1 * visitor.onText('Something')
+        1 * visitor.onEndJavadocTag('link')
+        0 * visitor._
+    }
+
+    def javadocTagCanContainEOLChars() {
+        when:
+        lexer.pushText(" * {@link #Something(Object,\n * String\n * }")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartJavadocTag('link')
+        1 * visitor.onText('#Something(Object,\nString\n')
+        1 * visitor.onEndJavadocTag('link')
+        0 * visitor._
+    }
+
+    def doesNotParseHtmlElementsInsideJavadocTag() {
+        when:
+        lexer.pushText("{@link <something> & < </something>}")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onStartJavadocTag('link')
+        1 * visitor.onText('<something> & < </something>')
+        1 * visitor.onEndJavadocTag('link')
+        0 * visitor._
+    }
+
+    def javadocTagCannotHaveWhitespaceInsideMarker() {
+        when:
+        lexer.pushText("{ @code} {@ code} { @ code}")
+        lexer.visit(visitor)
+
+        then:
+        1 * visitor.onText('{ @code} ')
+        1 * visitor.onStartJavadocTag('')
+        1 * visitor.onText('code')
+        1 * visitor.onEndJavadocTag('')
+        1 * visitor.onText(' { @ code}')
+        0 * visitor._
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
new file mode 100644
index 0000000..b5c98f4
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.dsl.model.PropertyMetaData
+import org.gradle.build.docs.dsl.model.TypeMetaData
+import org.gradle.build.docs.dsl.model.MethodMetaData
+import org.gradle.build.docs.dsl.model.ParameterMetaData
+
+class ClassDocRendererTest extends XmlSpecification {
+    final LinkRenderer linkRenderer = linkRenderer()
+    final ClassDocRenderer renderer = new ClassDocRenderer(linkRenderer)
+
+    def mergesClassMetaDataIntoMainSection() {
+        def content = parse('''
+            <chapter>
+                <para>Some custom content</para>
+            </chapter>
+        ''')
+
+        ClassDoc classDoc = classDoc('org.gradle.Class', id: 'classId', content: content, comment: 'class comment')
+
+        when:
+        withCategories {
+            renderer.mergeDescription(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter id="classId">
+    <title>Class</title>
+    <segmentedlist>
+        <segtitle>API Documentation</segtitle>
+        <seglistitem>
+            <seg>
+                <apilink class="org.gradle.Class" style="java"/>
+            </seg>
+        </seglistitem>
+    </segmentedlist>
+    <para>class comment</para>
+    <para>Some custom content</para>
+</chapter>'''
+    }
+    
+    def mergesPropertyMetaDataIntoPropertiesSection() {
+        def content = parse('''
+            <chapter>
+                <section><title>Properties</title>
+                    <table>
+                        <thead><tr><td>Name</td><td>Extra column</td></tr></thead>
+                        <tr><td>propName</td><td>some value</td></tr>
+                    </table>
+                </section>
+            </chapter>
+        ''')
+
+        ClassDoc classDoc = classDoc('Class', content: content)
+        PropertyDoc propDoc = propertyDoc('propName', id: 'propId', description: 'prop description', comment: 'prop comment', type: 'org.gradle.Type')
+        _ * classDoc.classProperties >> [propDoc]
+        _ * propDoc.additionalValues >> [new ExtraAttributeDoc(parse('<td>Extra column</td>'), parse('<td>some value</td>'))]
+
+        when:
+        withCategories {
+            renderer.mergeProperties(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Properties</title>
+        <table>
+            <title>Properties - Class</title>
+            <thead>
+                <tr>
+                    <td>Property</td>
+                    <td>Description</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>
+                    <link linkend="propId">
+                        <literal>propName</literal>
+                    </link>
+                </td>
+                <td>
+                    <para>prop description</para>
+                </td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Property details</title>
+        <section id="propId" role="detail">
+            <title><classname>org.gradle.Type</classname> <literal>propName</literal> (read-only)</title>
+            <para>prop comment</para>
+            <segmentedlist>
+                <segtitle>Extra column</segtitle>
+                <seglistitem>
+                    <seg>some value</seg>
+                </seglistitem>
+            </segmentedlist>
+        </section>
+    </section>
+</chapter>'''
+    }
+
+    def removesPropertiesTableWhenClassHasNoProperties() {
+        def content = parse('''
+            <chapter>
+                <section><title>Properties</title>
+                    <table>
+                        <thead><tr><td>Name</td></tr></thead>
+                    </table>
+                </section>
+            </chapter>
+        ''')
+
+        ClassDoc classDoc = classDoc('Class', content: content)
+        _ * classDoc.classProperties >> []
+
+        when:
+        withCategories {
+            renderer.mergeProperties(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Properties</title>
+        <para>No properties</para>
+    </section>
+</chapter>'''
+    }
+
+    def mergesExtensionPropertyMetaDataIntoPropertiesSection() {
+        def content = parse('''<chapter>
+                <section><title>Properties</title>
+                    <table>
+                        <thead><tr><td>Name</td></tr></thead>
+                    </table>
+                </section>
+                <section><title>Property details</title></section>
+            </chapter>
+        ''')
+
+        ClassDoc targetClassDoc = classDoc('Class', content: content)
+        ClassExtensionDoc extensionDoc = extensionDoc('thingo')
+        PropertyDoc propertyDoc = propertyDoc('propName', id: 'propId')
+        _ * targetClassDoc.classExtensions >> [extensionDoc]
+        _ * extensionDoc.extensionProperties >> [propertyDoc]
+
+        when:
+        withCategories {
+            renderer.mergeExtensionProperties(targetClassDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+        <section>
+            <title>Properties added by the <literal>thingo</literal> plugin</title>
+            <titleabbrev><literal>thingo</literal> plugin</titleabbrev>
+            <table>
+                <title>Properties - <literal>thingo</literal> plugin</title>
+                <thead>
+                    <tr>
+                        <td>Property</td>
+                        <td>Description</td>
+                    </tr>
+                </thead>
+                <tr>
+                    <td>
+                        <link linkend="propId">
+                            <literal>propName</literal>
+                        </link>
+                    </td>
+                    <td>
+                        <para>description</para>
+                    </td>
+                </tr>
+            </table>
+        </section>
+    </section>
+    <section>
+        <title>Property details</title>
+        <section id="propId" role="detail">
+            <title><classname>SomeType</classname> <literal>propName</literal> (read-only)</title>
+            <para>comment</para>
+        </section>
+    </section>
+</chapter>'''
+    }
+
+    def mergesMethodMetaDataIntoMethodsSection() {
+        def content = parse('''
+            <chapter>
+                <section><title>Methods</title>
+                    <table>
+                        <thead><tr><td>Name</td></tr></thead>
+                        <tr><td>methodName</td></tr>
+                    </table>
+                </section>
+            </chapter>
+        ''')
+
+        ClassDoc classDoc = classDoc('Class', content: content)
+        MethodDoc method1 = methodDoc('methodName', id: 'method1Id', returnType: 'ReturnType1', description: 'method description', comment: 'method comment')
+        MethodDoc method2 = methodDoc('methodName', id: 'method2Id', returnType: 'ReturnType2', description: 'overloaded description', comment: 'overloaded comment', paramTypes: ['ParamType'])
+        _ * classDoc.classMethods >> [method1, method2]
+
+
+        when:
+        withCategories {
+            renderer.mergeMethods(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Methods</title>
+        <table>
+            <title>Methods - Class</title>
+            <thead>
+                <tr>
+                    <td>Method</td>
+                    <td>Description</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>
+                    <literal><link linkend="method1Id">methodName</link>()</literal>
+                </td>
+                <td>
+                    <para>method description</para>
+                </td>
+            </tr>
+            <tr>
+                <td>
+                    <literal><link linkend="method2Id">methodName</link>(p)</literal>
+                </td>
+                <td>
+                    <para>overloaded description</para>
+                </td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Method details</title>
+        <section id="method1Id" role="detail">
+            <title><classname>ReturnType1</classname> <literal>methodName</literal>()</title>
+            <para>method comment</para>
+        </section>
+        <section id="method2Id" role="detail">
+            <title><classname>ReturnType2</classname> <literal>methodName</literal>(<classname>ParamType</classname> p)</title>
+            <para>overloaded comment</para>
+        </section>
+    </section>
+</chapter>'''
+    }
+
+    def mergesExtensionMethodMetaDataIntoMethodsSection() {
+        def content = parse('''
+            <chapter>
+                <section><title>Methods</title>
+                    <table>
+                        <thead><tr><td>Name</td></tr></thead>
+                    </table>
+                </section>
+                <section><title>Method details</title></section>
+            </chapter>
+        ''')
+
+        ClassDoc targetClassDoc = classDoc('Class', content: content)
+        ClassExtensionDoc extensionDoc = extensionDoc('thingo')
+        MethodDoc methodDoc = methodDoc('methodName', id: 'methodId')
+        _ * targetClassDoc.classExtensions >> [extensionDoc]
+        _ * extensionDoc.extensionMethods >> [methodDoc]
+
+        when:
+        withCategories {
+            renderer.mergeExtensionMethods(targetClassDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+        <section>
+            <title>Methods added by the <literal>thingo</literal> plugin</title>
+            <titleabbrev><literal>thingo</literal> plugin</titleabbrev>
+            <table>
+                <title>Methods - <literal>thingo</literal> plugin</title>
+                <thead>
+                    <tr>
+                        <td>Method</td>
+                        <td>Description</td>
+                    </tr>
+                </thead>
+                <tr>
+                    <td>
+                        <literal><link linkend="methodId">methodName</link>()</literal>
+                    </td>
+                    <td>
+                        <para>description</para>
+                    </td>
+                </tr>
+            </table>
+        </section>
+    </section>
+    <section>
+        <title>Method details</title>
+        <section id="methodId" role="detail">
+            <title><classname>ReturnType</classname> <literal>methodName</literal>()</title>
+            <para>comment</para>
+        </section>
+    </section>
+</chapter>'''
+    }
+
+    def removesMethodsTableWhenClassHasNoMethods() {
+        def content = parse('''
+            <chapter>
+                <section><title>Methods</title>
+                    <table>
+                        <thead><tr><td>Name</td></tr></thead>
+                    </table>
+                </section>
+            </chapter>
+        ''')
+
+        ClassDoc classDoc = classDoc('Class', content: content)
+        _ * classDoc.classMethods >> []
+
+        when:
+        withCategories {
+            renderer.mergeMethods(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Methods</title>
+        <para>No methods</para>
+    </section>
+</chapter>'''
+    }
+
+    def mergesBlockMetaDataIntoBlocksSection() {
+        def content = parse('''
+            <chapter>
+                <section>
+                    <title>Methods</title>
+                </section>
+            </chapter>
+        ''')
+        ClassDoc classDoc = classDoc('Class', content: content)
+        BlockDoc block = blockDoc('block', id: 'blockId', description: 'block description', comment: 'block comment', type: 'org.gradle.Type')
+        _ * classDoc.classBlocks >> [block]
+
+        when:
+        withCategories {
+            renderer.mergeBlocks(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Script blocks</title>
+        <table>
+            <title>Script blocks - Class</title>
+            <thead>
+                <tr>
+                    <td>Block</td>
+                    <td>Description</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>
+                    <link linkend="blockId">
+                        <literal>block</literal>
+                    </link>
+                </td>
+                <td>
+                    <para>block description</para>
+                </td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Script block details</title>
+        <section id="blockId" role="detail">
+            <title><literal>block</literal> { }</title>
+            <para>block comment</para>
+            <segmentedlist>
+                <segtitle>Delegates to</segtitle>
+                <seglistitem>
+                    <seg><classname>org.gradle.Type</classname> from <link linkend="block">
+                            <literal>block</literal></link></seg>
+                </seglistitem>
+            </segmentedlist>
+        </section>
+    </section>
+    <section>
+        <title>Methods</title>
+    </section>
+</chapter>'''
+    }
+
+    def mergesExtensionBlockMetaDataIntoBlocksSection() {
+        def content = parse('''
+            <chapter>
+                <section><title>Script blocks</title>
+                    <table><thead/></table>
+                </section>
+                <section><title>Script block details</title></section>
+            </chapter>
+        ''')
+
+        ClassDoc targetClassDoc = classDoc('Class', content: content)
+        ClassExtensionDoc extensionDoc = extensionDoc('thingo')
+        BlockDoc blockDoc = blockDoc('blockName', id: 'blockId')
+        _ * targetClassDoc.classExtensions >> [extensionDoc]
+        _ * extensionDoc.extensionBlocks >> [blockDoc]
+
+        when:
+        withCategories {
+            renderer.mergeExtensionBlocks(targetClassDoc)
+        }
+
+        then:
+        formatTree(content) == '''<chapter>
+    <section>
+        <title>Script blocks</title>
+        <table>
+            <thead/>
+        </table>
+        <section>
+            <title>Script blocks added by the <literal>thingo</literal> plugin</title>
+            <titleabbrev><literal>thingo</literal> plugin</titleabbrev>
+            <table>
+                <title>Script blocks - <literal>thingo</literal> plugin</title>
+                <thead>
+                    <tr>
+                        <td>Block</td>
+                        <td>Description</td>
+                    </tr>
+                </thead>
+                <tr>
+                    <td>
+                        <link linkend="blockId">
+                            <literal>blockName</literal>
+                        </link>
+                    </td>
+                    <td>
+                        <para>description</para>
+                    </td>
+                </tr>
+            </table>
+        </section>
+    </section>
+    <section>
+        <title>Script block details</title>
+        <section id="blockId" role="detail">
+            <title><literal>blockName</literal> { }</title>
+            <para>comment</para>
+            <segmentedlist>
+                <segtitle>Delegates to</segtitle>
+                <seglistitem>
+                    <seg><classname>BlockType</classname> from <link linkend="blockName">
+                            <literal>blockName</literal></link></seg>
+                </seglistitem>
+            </segmentedlist>
+        </section>
+    </section>
+</chapter>'''
+    }
+
+    def doesNotAddBlocksTableWhenClassHasNoScriptBlocks() {
+        def content = parse('''
+            <section>
+                <section><title>Methods</title></section>
+            </section>
+        ''')
+
+        ClassDoc classDoc = classDoc('Class', content: content)
+        _ * classDoc.classBlocks >> []
+
+        when:
+        withCategories {
+            renderer.mergeBlocks(classDoc)
+        }
+
+        then:
+        formatTree(content) == '''<section>
+    <section>
+        <title>Script blocks</title>
+        <para>No script blocks</para>
+    </section>
+    <section>
+        <title>Methods</title>
+    </section>
+</section>'''
+    }
+
+    def linkRenderer() {
+        LinkRenderer renderer = Mock()
+        _ * renderer.link(!null, !null) >> {
+            args -> parse("<classname>${args[0].signature}</classname>")
+        }
+        return renderer
+    }
+
+    def classDoc(Map<String, ?> args = [:], String name) {
+        ClassDoc classDoc = Mock()
+        def content = args.content ?: parse('<section></section>')
+        def propertiesSection = withCategories { content.section.find { it.title[0].text().trim() == 'Properties' } }
+        def propertyDetailsSection = withCategories { content.section.find { it.title[0].text().trim() == 'Property details' } }
+        def propertiesTable = withCategories { propertiesSection ? propertiesSection.table[0] : parse('<table/>')}
+        def methodsSection = withCategories { content.section.find { it.title[0].text().trim() == 'Methods' } }
+        def methodDetailsSection = withCategories { content.section.find { it.title[0].text().trim() == 'Method details' } }
+        def methodsTable = withCategories { methodsSection ? methodsSection.table[0] : parse('<table/>') }
+        def blocksSection = withCategories { content.section.find { it.title[0].text().trim() == 'Script blocks' } }
+        def blockDetailsSection = withCategories { content.section.find { it.title[0].text().trim() == 'Script block details' } }
+        def blocksTable = withCategories { blocksSection ? blocksSection.table[0] : parse('<table/>') }
+        _ * classDoc.simpleName >> name.split('\\.').last()
+        _ * classDoc.name >> name
+        _ * classDoc.id >> (args.id ?: name)
+        _ * classDoc.classSection >> content
+        _ * classDoc.propertiesSection >> propertiesSection
+        _ * classDoc.propertiesTable >> propertiesTable
+        _ * classDoc.propertyDetailsSection >> propertyDetailsSection
+        _ * classDoc.methodsSection >> methodsSection
+        _ * classDoc.methodsTable >> methodsTable
+        _ * classDoc.methodDetailsSection >> methodDetailsSection
+        _ * classDoc.blocksTable >> blocksTable
+        _ * classDoc.blockDetailsSection >> blockDetailsSection
+        _ * classDoc.description >> parse("<para>${args.description ?: 'description'}</para>")
+        _ * classDoc.comment >> [parse("<para>${args.comment ?: 'comment'}</para>")]
+        _ * classDoc.style >> 'java'
+        return classDoc
+    }
+
+    def propertyDoc(Map<String, ?> args = [:], String name) {
+        PropertyDoc propDoc = Mock()
+        PropertyMetaData propMetaData = Mock()
+        _ * propDoc.name >> name
+        _ * propDoc.id >> (args.id ?: name)
+        _ * propDoc.description >> parse("<para>${args.description ?: 'description'}</para>")
+        _ * propDoc.comment >> [parse("<para>${args.comment ?: 'comment'}</para>")]
+        _ * propDoc.metaData >> propMetaData
+        _ * propMetaData.type >> new TypeMetaData(args.type ?: 'SomeType')
+        return propDoc
+    }
+
+    def methodDoc(Map<String, ?> args = [:], String name) {
+        MethodDoc methodDoc = Mock()
+        MethodMetaData metaData = Mock()
+        _ * methodDoc.name >> name
+        _ * methodDoc.id >> args.id
+        _ * methodDoc.description >> parse("<para>${args.description ?: 'description'}</para>")
+        _ * methodDoc.comment >> [parse("<para>${args.comment ?: 'comment'}</para>")]
+        _ * methodDoc.metaData >> metaData
+        _ * metaData.returnType >> new TypeMetaData(args.returnType ?: 'ReturnType')
+        def paramTypes = args.paramTypes ?: []
+        _ * metaData.parameters >> paramTypes.collect {
+            def param = new ParameterMetaData("p", metaData);
+            param.type = new TypeMetaData(it)
+            return param
+        }
+        return methodDoc
+    }
+
+    def blockDoc(Map<String, ?> args = [:], String name) {
+        BlockDoc blockDoc = Mock()
+        PropertyDoc blockPropDoc = propertyDoc(name)
+        _ * blockDoc.name >> name
+        _ * blockDoc.id >> (args.id ?: name)
+        _ * blockDoc.description >> parse("<para>${args.description ?: 'description'}</para>")
+        _ * blockDoc.comment >> [parse("<para>${args.comment ?: 'comment'}</para>")]
+        _ * blockDoc.type >> new TypeMetaData(args.type ?: 'BlockType')
+        _ * blockDoc.blockProperty >> blockPropDoc
+        blockDoc
+    }
+
+    def extensionDoc(Map<String, ?> args = [:], String name) {
+        ClassExtensionDoc doc = Mock()
+        doc.pluginId >> name
+        doc
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy
new file mode 100644
index 0000000..248f9ce
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.dsl.model.*
+
+class ClassDocTest extends XmlSpecification {
+    final JavadocConverter javadocConverter = Mock()
+    final DslDocModel docModel = Mock()
+
+    def buildsPropertiesForClass() {
+        ClassMetaData classMetaData = classMetaData()
+        PropertyMetaData propertyA = property('a', classMetaData, comment: 'prop a')
+        PropertyMetaData propertyB = property('b', classMetaData, comment: 'prop b')
+        ClassDoc superDoc = classDoc()
+        PropertyDoc propertyDocA = propertyDoc('a')
+        PropertyDoc propertyDocC = propertyDoc('c')
+
+        def content = parse('''
+<section>
+    <section><title>Properties</title>
+        <table>
+            <thead><tr><td>Name</td></tr></thead>
+            <tr><td>b</td></tr>
+            <tr><td>a</td></tr>
+        </table>
+    </section>
+    <section><title>Methods</title><table><thead><tr></tr></thead></table></section>
+</section>
+''')
+
+        when:
+        ClassDoc doc = withCategories {
+            new ClassDoc('org.gradle.Class', content, document, classMetaData, null, docModel, javadocConverter).buildProperties()
+        }
+
+        then:
+        doc.classProperties.size() == 3
+        doc.classProperties[0].name == 'a'
+        doc.classProperties[1].name == 'b'
+        doc.classProperties[2].name == 'c'
+
+        _ * classMetaData.findProperty('b') >> propertyB
+        _ * classMetaData.findProperty('a') >> propertyA
+        _ * classMetaData.superClassName >> 'org.gradle.SuperType'
+        _ * docModel.getClassDoc('org.gradle.SuperType') >> superDoc
+        _ * superDoc.getClassProperties() >> [propertyDocC, propertyDocA]
+    }
+
+    def canAttachAdditionalValuesToProperty() {
+        ClassMetaData classMetaData = classMetaData()
+        PropertyMetaData propertyA = property('a', classMetaData, comment: 'prop a')
+        PropertyMetaData propertyB = property('b', classMetaData, comment: 'prop b')
+        ClassDoc superDoc = classDoc()
+        ExtraAttributeDoc inheritedValue = new ExtraAttributeDoc(parse('<td>inherited</td>'), parse('<td>inherited</td>'))
+        ExtraAttributeDoc overriddenValue = new ExtraAttributeDoc(parse('<td>general value</td>'), parse('<td>general</td>'))
+        PropertyDoc inheritedPropertyA = propertyDoc('a', additionalValues: [inheritedValue, overriddenValue])
+        PropertyDoc inheritedPropertyB = propertyDoc('b', additionalValues: [inheritedValue, overriddenValue])
+        PropertyDoc inheritedPropertyC = propertyDoc('c', additionalValues: [inheritedValue, overriddenValue])
+
+        def content = parse('''
+<section>
+    <section><title>Properties</title>
+        <table>
+            <thead><tr><td>Name</td><td>inherited</td><td>added</td><td>overridden <overrides>general value</overrides></td></tr></thead>
+            <tr><td>a</td><td>specific1</td><td>specific2</td><td>specific3</td></tr>
+            <tr><td>b</td><td></td><td/><td/></tr>
+        </table>
+    </section>
+    <section><title>Methods</title><table><thead><tr></tr></thead></table></section>
+</section>
+''')
+
+        when:
+        ClassDoc doc = withCategories {
+            new ClassDoc('org.gradle.Class', content, document, classMetaData, null, docModel, javadocConverter).buildProperties()
+        }
+
+        then:
+        doc.classProperties.size() == 3
+
+        def prop = doc.classProperties[0]
+        prop.name == 'a'
+        prop.additionalValues.size() == 3
+        format(prop.additionalValues[0].title) == 'inherited'
+        format(prop.additionalValues[0].value) == 'specific1'
+        format(prop.additionalValues[1].title) == 'overridden'
+        format(prop.additionalValues[1].value) == 'specific3'
+        format(prop.additionalValues[2].title) == 'added'
+        format(prop.additionalValues[2].value) == 'specific2'
+
+        prop = doc.classProperties[1]
+        prop.name == 'b'
+        prop.additionalValues.size() == 2
+        format(prop.additionalValues[0].title) == 'inherited'
+        format(prop.additionalValues[0].value) == 'inherited'
+        format(prop.additionalValues[1].title) == 'overridden'
+        format(prop.additionalValues[1].value) == 'general'
+
+        prop = doc.classProperties[2]
+        prop.name == 'c'
+        prop.additionalValues.size() == 2
+        format(prop.additionalValues[0].title) == 'inherited'
+        format(prop.additionalValues[0].value) == 'inherited'
+        format(prop.additionalValues[1].title) == 'overridden'
+        format(prop.additionalValues[1].value) == 'general'
+
+        _ * classMetaData.findProperty('b') >> propertyB
+        _ * classMetaData.findProperty('a') >> propertyA
+        _ * classMetaData.superClassName >> 'org.gradle.SuperType'
+        _ * docModel.getClassDoc('org.gradle.SuperType') >> superDoc
+        _ * superDoc.classProperties >> [inheritedPropertyA, inheritedPropertyB, inheritedPropertyC]
+    }
+
+    def buildsMethodsForClass() {
+        ClassMetaData classMetaData = classMetaData()
+        MethodMetaData methodA = method('a', classMetaData)
+        MethodMetaData methodB = method('b', classMetaData)
+        MethodMetaData methodBOverload = method('b', classMetaData)
+        MethodDoc methodAOverridden = methodDoc('a')
+        MethodDoc methodC = methodDoc('c')
+        ClassDoc superClass = classDoc('org.gradle.SuperClass')
+
+        def content = parse('''
+<section>
+    <section><title>Methods</title>
+        <table>
+            <thead><tr><td>Name</td></tr></thead>
+            <tr><td>a</td></tr>
+            <tr><td>b</td></tr>
+        </table>
+    </section>
+    <section><title>Properties</title><table><thead><tr>Name</tr></thead></table></section>
+</section>
+''')
+
+        when:
+        ClassDoc doc = withCategories {
+            new ClassDoc('org.gradle.Class', content, document, classMetaData, null, docModel, javadocConverter).buildMethods()
+        }
+
+        then:
+        doc.classMethods.size() == 4
+
+        doc.classMethods[0].name == 'a'
+        doc.classMethods[1].name == 'b'
+        doc.classMethods[2].name == 'b'
+        doc.classMethods[3].name == 'c'
+
+        _ * classMetaData.declaredMethods >> ([methodA, methodB, methodBOverload] as Set)
+        _ * classMetaData.superClassName >> 'org.gradle.SuperClass'
+        _ * docModel.getClassDoc('org.gradle.SuperClass') >> superClass
+        _ * superClass.classMethods >> [methodC, methodAOverridden]
+    }
+
+    def buildsBlocksForClass() {
+        ClassMetaData classMetaData = classMetaData()
+        PropertyMetaData blockProperty = property('block', classMetaData)
+        MethodMetaData blockMethod = method('block', classMetaData, paramTypes: [Closure.class.name])
+        PropertyMetaData compositeBlockProperty = property('listBlock', classMetaData, type: new TypeMetaData('java.util.List').addTypeArg(new TypeMetaData('BlockType')))
+        MethodMetaData compositeBlockMethod = method('listBlock', classMetaData, paramTypes: [Closure.class.name])
+        MethodMetaData tooManyParams = method('block', classMetaData, paramTypes: ['String', 'boolean'])
+        MethodMetaData notAClosure = method('block', classMetaData, paramTypes: ['String'])
+        MethodMetaData noBlockProperty = method('notBlock', classMetaData, paramTypes: [Closure.class.name])
+        _ * classMetaData.findProperty('block') >> blockProperty
+        _ * classMetaData.findProperty('listBlock') >> compositeBlockProperty
+        _ * classMetaData.declaredMethods >> [blockMethod, compositeBlockMethod, tooManyParams, notAClosure, noBlockProperty]
+
+        def content = parse('''
+<section>
+    <section><title>Methods</title>
+        <table>
+            <thead><tr><td>Name</td></tr></thead>
+            <tr><td>block</td></tr>
+            <tr><td>listBlock</td></tr>
+            <tr><td>notBlock</td></tr>
+        </table>
+    </section>
+    <section><title>Properties</title>
+        <table>
+            <thead><tr><td>Name</td></tr></thead>
+            <tr><td>block</td></tr>
+            <tr><td>listBlock</td></tr>
+        </table>
+    </section>
+</section>
+''')
+
+        when:
+        ClassDoc doc = withCategories {
+            new ClassDoc('org.gradle.Class', content, document, classMetaData, null, docModel, javadocConverter).buildProperties().buildMethods()
+        }
+
+        then:
+        doc.classProperties.size() == 2
+        doc.classProperties[0].name == 'block'
+        doc.classProperties[1].name == 'listBlock'
+
+        doc.classMethods.size() == 3
+
+        doc.classBlocks.size() == 2
+        doc.classBlocks[0].name == 'block'
+        doc.classBlocks[0].type.signature == 'org.gradle.Type'
+        !doc.classBlocks[0].multiValued
+
+        doc.classBlocks[1].name == 'listBlock'
+        doc.classBlocks[1].type.signature == 'BlockType'
+        doc.classBlocks[1].multiValued
+    }
+
+    def buildsExtensionsForClass() {
+        ClassMetaData classMetaData = classMetaData()
+        ExtensionMetaData extensionMetaData = new ExtensionMetaData('org.gradle.Class')
+        extensionMetaData.add('a', 'org.gradle.ExtensionA1')
+        extensionMetaData.add('a', 'org.gradle.ExtensionA2')
+        extensionMetaData.add('b', 'org.gradle.ExtensionB')
+        ClassDoc extensionA1 = classDoc('org.gradle.ExtensionA1')
+        ClassDoc extensionA2 = classDoc('org.gradle.ExtensionA2')
+        ClassDoc extensionB = classDoc('org.gradle.ExtensionB')
+        _ * docModel.getClassDoc('org.gradle.ExtensionA1') >> extensionA1
+        _ * docModel.getClassDoc('org.gradle.ExtensionA2') >> extensionA2
+        _ * docModel.getClassDoc('org.gradle.ExtensionB') >> extensionB
+
+        def content = parse('''<section>
+                <section><title>Properties</title>
+                    <table><thead><tr><td/></tr></thead></table>
+                </section>
+                <section><title>Methods</title>
+                    <table><thead><tr><td/></tr></thead></table>
+                </section>
+            </section>
+        ''')
+
+        when:
+        ClassDoc doc = withCategories {
+            new ClassDoc('org.gradle.Class', content, document, classMetaData, extensionMetaData, docModel, javadocConverter).buildExtensions()
+        }
+
+        then:
+        doc.classExtensions.size() == 2
+
+        doc.classExtensions[0].pluginId == 'a'
+        doc.classExtensions[0].extensionClasses == [extensionA1, extensionA2]
+
+        doc.classExtensions[1].pluginId == 'b'
+        doc.classExtensions[1].extensionClasses == [extensionB]
+    }
+
+    def classMetaData(String name = 'org.gradle.Class') {
+        ClassMetaData classMetaData = Mock()
+        _ * classMetaData.className >> name
+        return classMetaData
+    }
+
+    def classDoc(String name = 'org.gradle.Class') {
+        ClassDoc doc = Mock()
+        _ * doc.name >> name
+        _ * doc.toString() >> "ClassDoc '$name'"
+        return doc
+    }
+
+    def property(String name, ClassMetaData classMetaData) {
+        return property([:], name, classMetaData)
+    }
+
+    def property(Map<String, ?> args, String name, ClassMetaData classMetaData) {
+        PropertyMetaData property = Mock()
+        _ * property.name >> name
+        _ * property.ownerClass >> classMetaData
+        def type = args.type instanceof TypeMetaData ? args.type : new TypeMetaData(args.type ?: 'org.gradle.Type')
+        _ * property.type >> type
+        _ * property.signature >> "$name-signature"
+        _ * javadocConverter.parse(property, !null) >> ({[parse("<para>${args.comment ?: 'comment'}</para>")]} as DocComment)
+        return property
+    }
+
+    def propertyDoc(Map<String, ?> args = [:], String name) {
+        return new PropertyDoc(classMetaData(), property(name, null), [parse("<para>$name comment</para>")], args.additionalValues)
+    }
+
+    def method(String name, ClassMetaData classMetaData) {
+        return method([:], name, classMetaData)
+    }
+
+    def method(Map<String, ?> args, String name, ClassMetaData classMetaData) {
+        MethodMetaData method = Mock()
+        List<String> paramTypes = args.paramTypes ?: []
+        _ * method.name >> name
+        _ * method.overrideSignature >> "$name(${paramTypes.join(', ')})"
+        _ * method.parameters >> paramTypes.collect {
+            def param = new ParameterMetaData("p", method);
+            param.type = new TypeMetaData(it)
+            return param
+        }
+        _ * method.ownerClass >> classMetaData
+        _ * method.returnType >> new TypeMetaData(args.returnType ?: 'ReturnType')
+        _ * javadocConverter.parse(method, !null) >> ({[parse("<para>${args.comment ?: 'comment'}</para>")]} as DocComment)
+        return method
+    }
+
+    def methodDoc(String name) {
+        MethodDoc methodDoc = Mock()
+        _ * methodDoc.name >> name
+        _ * methodDoc.metaData >> method(name, null)
+        _ * methodDoc.forClass(!null) >> methodDoc
+        return methodDoc
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy
new file mode 100644
index 0000000..0e770ba
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.dsl.model.PropertyMetaData
+import org.gradle.build.docs.dsl.model.MethodMetaData
+
+class JavadocConverterTest extends XmlSpecification {
+    final ClassMetaData classMetaData = Mock()
+    final JavadocLinkConverter linkConverter = Mock()
+    final GenerationListener listener = Mock()
+    final JavadocConverter parser = new JavadocConverter(document, linkConverter)
+
+    def removesLeadingAsterixFromEachLine() {
+        _ * classMetaData.rawCommentText >> ''' * line 1
+ * line 2
+'''
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>line 1
+line 2</para>'''
+    }
+
+    def removesTagBlockFromComment() {
+        _ * classMetaData.rawCommentText >> ''' * line 1
+ * @tag line 2
+ * line 3
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>line 1</para>'''
+    }
+
+    def ignoresLeadingAndTrailingEmptyLines() {
+        _ * classMetaData.rawCommentText >> ''' *
+ * line 1
+ *
+ * @tag line 2
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>line 1</para>'''
+    }
+
+    def commentIsEmptyWhenThereIsNoDescription() {
+        _ * classMetaData.rawCommentText >> ''' *
+ *
+ * @tag line 2
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        result.docbook == []
+    }
+
+    def commentCanContainHtmlEncodedCharacters() {
+        _ * classMetaData.rawCommentText >> ''' * <>& />'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><>& /></para>'''
+    }
+
+    def convertsPElementsToParaElements() {
+        _ * classMetaData.rawCommentText >> '<p>para 1</p><P>para 2</P>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>para 1</para><para>para 2</para>'''
+    }
+
+    def addsImplicitParaElement() {
+        _ * classMetaData.rawCommentText >> '<em>para 1</em><P>para 2</P>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><emphasis>para 1</emphasis></para><para>para 2</para>'''
+    }
+
+    def ignoresEmptyPElements() {
+        _ * classMetaData.rawCommentText >> 'para 1<p/><p></p>para 2<p></p>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>para 1</para><para>para 2</para>'''
+    }
+
+    def convertsCodeTagsAndElementsToLiteralElements() {
+        _ * classMetaData.rawCommentText >> 'This is <code>code</code>. So is {@code this}.'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>This is <literal>code</literal>. So is <literal>this</literal>.</para>'''
+    }
+
+    def doesNotInterpretContentsOfCodeTagAsHtml() {
+        _ * classMetaData.rawCommentText >> '{@code List<String> && a < 9} <code>&</code>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><literal>List<String> && a < 9</literal> <literal>&</literal></para>'''
+    }
+
+    def convertsPreElementsToProgramListingElements() {
+        _ * classMetaData.rawCommentText >> ''' * <pre>this is some
+ *
+ * literal code</pre>
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<programlisting>this is some
+
+literal code</programlisting>'''
+    }
+
+    def implicitlyEndsCurrentParagraphAtNextBlockElement() {
+        _ * classMetaData.rawCommentText >> ''' * for example: <pre>this is some
+ * literal code</pre> does something.
+<p>another para.
+<ul><li>item1</li></ul>
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>for example: </para><programlisting>this is some
+literal code</programlisting><para> does something.
+</para><para>another para.
+</para><itemizedlist><listitem>item1</listitem></itemizedlist>'''
+    }
+
+    def implicitlyEndsCurrentLiAtNextLiElement() {
+        _ * classMetaData.rawCommentText >> '''<ul><li>item 1<li>item 2</ul>'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<itemizedlist><listitem>item 1</listitem><listitem>item 2</listitem></itemizedlist>'''
+    }
+
+    def convertsUlAndLiElementsToItemizedListElements() {
+        _ * classMetaData.rawCommentText >> '<ul><li>item1</li></ul>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<itemizedlist><listitem>item1</listitem></itemizedlist>'''
+    }
+
+    def convertsOlAndLiElementsToOrderedListElements() {
+        _ * classMetaData.rawCommentText >> '<ol><li>item1</li></ol>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<orderedlist><listitem>item1</listitem></orderedlist>'''
+    }
+
+    def convertsALinkTag() {
+        _ * classMetaData.rawCommentText >> '{@link someClass} {@link otherClass#method(a, b) label}'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><xref/> <xref/></para>'''
+        1 * linkConverter.resolve('someClass', classMetaData, listener) >> document.createElement("xref")
+        1 * linkConverter.resolve('otherClass#method(a, b) label', classMetaData, listener) >> document.createElement("xref")
+        0 * linkConverter._
+    }
+
+    def convertsAnAElementWithNameAttribute() {
+        _ * classMetaData.rawCommentText >> '<a name="anchor"/>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '<anchor id="org.gradle.Class.anchor"/>'
+        _ * classMetaData.className >> 'org.gradle.Class'
+    }
+
+    def convertsAnAElementWithAUrlFragment() {
+        _ * classMetaData.rawCommentText >> '<a href="#anchor">some value</a>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '<para><link linkend="org.gradle.Class.anchor">some value</link></para>'
+        _ * classMetaData.className >> 'org.gradle.Class'
+    }
+
+    def convertsAnEmElementToAnEmphasisElement() {
+        _ * classMetaData.rawCommentText >> '<em>text</em>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><emphasis>text</emphasis></para>'''
+    }
+
+    def convertsBAndIElementToAnEmphasisElement() {
+        _ * classMetaData.rawCommentText >> '<i>text</i> <b>other</b>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><emphasis>text</emphasis> <emphasis>other</emphasis></para>'''
+    }
+
+    def convertsHeadingsToSections() {
+        _ * classMetaData.rawCommentText >> '''
+<h2>section1</h2>
+text1
+<h3>section 1.1</h3>
+text2
+<h2>section 2</h2>
+text3
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<section><title>section1</title>
+text1
+<section><title>section 1.1</title>
+text2
+</section></section><section><title>section 2</title>
+text3</section>'''
+    }
+
+    def convertsTable() {
+        _ * classMetaData.rawCommentText >> '''
+<table>
+    <tr><th>column1</th><th>column2</th></tr>
+    <tr><td>cell1</td><td>cell2</td></tr>
+</table>
+'''
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<table>
+    <thead><tr><td>column1</td><td>column2</td></tr></thead>
+    <tr><td>cell1</td><td>cell2</td></tr>
+</table>'''
+    }
+
+    def convertsPropertyGetterMethodCommentToPropertyComment() {
+        PropertyMetaData propertyMetaData = Mock()
+        _ * propertyMetaData.rawCommentText >> 'returns the name of the thing.'
+
+        when:
+        def result = parser.parse(propertyMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>The name of the thing.</para>'''
+    }
+
+    def convertsInheritDocTag() {
+        PropertyMetaData propertyMetaData = Mock()
+        PropertyMetaData overriddenMetaData = Mock()
+
+        when:
+        def result = parser.parse(propertyMetaData, listener)
+
+        then:
+        _ * propertyMetaData.rawCommentText >> 'before {@inheritDoc} after'
+        _ * propertyMetaData.overriddenProperty >> overriddenMetaData
+        _ * overriddenMetaData.rawCommentText >> ''' *
+ * <em>inherited value</em>
+ *
+'''
+        format(result.docbook) == '''<para>before </para><para><emphasis>inherited value</emphasis></para><para> after</para>'''
+    }
+
+    def convertsValueTag() {
+        PropertyMetaData propertyMetaData = Mock()
+
+        when:
+        def result = parser.parse(propertyMetaData, listener)
+
+        then:
+        _ * propertyMetaData.rawCommentText >> '{@value org.gradle.SomeClass#CONST}'
+        _ * propertyMetaData.ownerClass >> classMetaData
+        _ * linkConverter.resolveValue('org.gradle.SomeClass#CONST', classMetaData, listener) >> document.importNode(parse('<literal>some-value</literal>'), true)
+
+        format(result.docbook) == '''<para><literal>some-value</literal></para>'''
+    }
+
+    def convertsMethodComment() {
+        MethodMetaData methodMetaData = Mock()
+        _ * methodMetaData.rawCommentText >> 'a method.'
+
+        when:
+        def result = parser.parse(methodMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>a method.</para>'''
+    }
+
+    def convertsUnknownElementsAndTags() {
+        PropertyMetaData propertyMetaData = Mock()
+        _ * propertyMetaData.rawCommentText >> '<unknown>text</unknown><inheritDoc>{@unknown text}{@p text}{@ unknown}'
+
+        when:
+        def result = parser.parse(propertyMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para><UNHANDLED-ELEMENT><unknown>text</unknown></UNHANDLED-ELEMENT><UNHANDLED-ELEMENT><inheritdoc><UNHANDLED-TAG>{@unknown text}</UNHANDLED-TAG><UNHANDLED-TAG>{@p text}</UNHANDLED-TAG><UNHANDLED-TAG>{@ unknown}</UNHANDLED-TAG></UNHANDLED-ELEMENT></para>'''
+    }
+
+    def handlesMissingStartTags() {
+        _ * classMetaData.rawCommentText >> 'a para</b></p>'
+
+        when:
+        def result = parser.parse(classMetaData, listener)
+
+        then:
+        format(result.docbook) == '''<para>a para</para>'''
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy
new file mode 100644
index 0000000..0e2c856
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.TypeNameResolver
+import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.dsl.model.ClassMetaData
+import org.gradle.build.docs.model.ClassMetaDataRepository
+import org.gradle.build.docs.dsl.model.MethodMetaData
+
+class JavadocLinkConverterTest extends XmlSpecification {
+    final LinkRenderer linkRenderer = Mock()
+    final TypeNameResolver nameResolver = Mock()
+    final ClassMetaData classMetaData = Mock()
+    final ClassMetaDataRepository<ClassMetaData> repository = Mock()
+    final GenerationListener listener = Mock()
+    final JavadocLinkConverter converter = new JavadocLinkConverter(document, nameResolver, linkRenderer, repository)
+
+    def convertsClassNameToLink() {
+        when:
+        def link = converter.resolve('someName', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+        _ * nameResolver.resolve('someName', classMetaData) >> 'org.gradle.SomeClass'
+        _ * linkRenderer.link({it.name == 'org.gradle.SomeClass'}, listener) >> parse('<someLinkElement/>')
+    }
+
+    def convertsFullyQualifiedClassNameToLink() {
+        when:
+        def link = converter.resolve('org.gradle.SomeClass', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+        _ * nameResolver.resolve('org.gradle.SomeClass', classMetaData) >> 'org.gradle.SomeClass'
+        _ * linkRenderer.link({it.name == 'org.gradle.SomeClass'}, listener) >> parse('<someLinkElement/>')
+    }
+
+    def resolvesUnknownFullyQualifiedClassName() {
+        when:
+        def link = converter.resolve('org.gradle.SomeClass', classMetaData, listener)
+
+        then:
+        format(link) == '''<UNHANDLED-LINK>org.gradle.SomeClass</UNHANDLED-LINK>'''
+    }
+
+    def convertsClassAndMethodNameToLink() {
+        ClassMetaData targetClass = Mock()
+        MethodMetaData method = method('someName')
+        _ * nameResolver.resolve('SomeClass', classMetaData) >> 'org.gradle.SomeClass'
+        _ * repository.find('org.gradle.SomeClass') >> targetClass
+        _ * targetClass.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('SomeClass#someName', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodNameToLink() {
+        MethodMetaData method = method('someName')
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodSignatureToLink() {
+        MethodMetaData method = method('someName', signature: 'someName(org.gradle.SomeClass, java.lang.Object)')
+        _ * nameResolver.resolve('SomeClass', classMetaData) >>'org.gradle.SomeClass'
+        _ * nameResolver.resolve('Object', classMetaData) >>'java.lang.Object'
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName(SomeClass, Object)', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodSignatureWithNoParamsToLink() {
+        MethodMetaData method = method('someName', signature: 'someName()')
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName()', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodSignatureWithArrayTypeToLink() {
+        MethodMetaData method = method('someName', signature: 'someName(org.gradle.SomeClass[], java.lang.Object)')
+        _ * nameResolver.resolve('SomeClass', classMetaData) >>'org.gradle.SomeClass'
+        _ * nameResolver.resolve('Object', classMetaData) >>'java.lang.Object'
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName(SomeClass[], Object)', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodNameWithLabelToLink() {
+        MethodMetaData method = method('someName')
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName this is the label.', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsMethodSignatureWithLabelToLink() {
+        MethodMetaData method = method('someName', signature: 'someName(org.gradle.SomeClass, java.lang.Object)')
+        _ * nameResolver.resolve('SomeClass', classMetaData) >>'org.gradle.SomeClass'
+        _ * nameResolver.resolve('Object', classMetaData) >>'java.lang.Object'
+        _ * classMetaData.declaredMethods >> ([method] as Set)
+        _ * linkRenderer.link(method, listener) >> parse('<someLinkElement/>')
+
+        when:
+        def link = converter.resolve('#someName(SomeClass, Object) this is a label', classMetaData, listener)
+
+        then:
+        format(link) == '<someLinkElement/>'
+    }
+
+    def convertsValueLinkToLiteralValue() {
+        ClassMetaData otherClass = Mock()
+
+        when:
+        def link = converter.resolveValue('SomeName#someField', classMetaData, listener)
+
+        then:
+        format(link) == '<literal>value</literal>'
+        _ * nameResolver.resolve('SomeName', classMetaData) >> 'org.gradle.SomeName'
+        _ * repository.find('org.gradle.SomeName') >> otherClass
+        _ * otherClass.constants >> [someField: 'value']
+    }
+
+    def convertsValueLinkInSameClassToLiteralValue() {
+        when:
+        def link = converter.resolveValue('#someField', classMetaData, listener)
+
+        then:
+        format(link) == '<literal>value</literal>'
+        _ * classMetaData.constants >> [someField: 'value']
+    }
+
+    private MethodMetaData method(Map<String, ?> args = [:], String name) {
+        def MethodMetaData method = Mock()
+        _ * method.name >> name
+        _ * method.overrideSignature >> args.signature
+        return method
+    }
+}
+
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy
new file mode 100644
index 0000000..d9a05e8
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.docbook
+
+import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.dsl.model.TypeMetaData
+import org.gradle.build.docs.dsl.model.MethodMetaData
+import org.gradle.build.docs.dsl.model.ClassMetaData
+
+class LinkRendererTest extends XmlSpecification {
+    final DslDocModel model = Mock()
+    final GenerationListener listener = Mock()
+    final LinkRenderer renderer = new LinkRenderer(document, model)
+
+    def rendersLinkToApiClass() {
+        when:
+        def link = renderer.link(type('org.gradle.SomeClass'), listener)
+
+        then:
+        format(link) == '<apilink class="org.gradle.SomeClass"/>'
+        _ * model.isKnownType('org.gradle.SomeClass') >> true
+    }
+
+    def rendersLinkToApiClassArray() {
+        when:
+        def link = renderer.link(type('org.gradle.SomeClass', true), listener)
+
+        then:
+        format(link) == '<classname><apilink class="org.gradle.SomeClass"/>[]</classname>'
+        _ * model.isKnownType('org.gradle.SomeClass') >> true
+    }
+
+    def rendersLinkToJavaClass() {
+        when:
+        def link = renderer.link(type('java.util.List'), listener)
+
+        then:
+        format(link) == '<ulink url="http://download.oracle.com/javase/1.5.0/docs/api/java/util/List.html"><classname>List</classname></ulink>'
+    }
+
+    def rendersLinkToJavaClassArray() {
+        when:
+        def link = renderer.link(type('java.util.List', true), listener)
+
+        then:
+        format(link) == '<classname><ulink url="http://download.oracle.com/javase/1.5.0/docs/api/java/util/List.html"><classname>List</classname></ulink>[]</classname>'
+    }
+
+    def rendersLinkToPrimitiveType() {
+        when:
+        def link = renderer.link(type('boolean'), listener)
+
+        then:
+        format(link) == '<classname>boolean</classname>'
+    }
+
+    def rendersLinkToGroovyClass() {
+        when:
+        def link = renderer.link(type('groovy.lang.Closure'), listener)
+
+        then:
+        format(link) == '<ulink url="http://groovy.codehaus.org/gapi/groovy/lang/Closure.html"><classname>Closure</classname></ulink>'
+    }
+
+    def rendersLinkToGroovyClassArray() {
+        when:
+        def link = renderer.link(type('groovy.lang.Closure', true), listener)
+
+        then:
+        format(link) == '<classname><ulink url="http://groovy.codehaus.org/gapi/groovy/lang/Closure.html"><classname>Closure</classname></ulink>[]</classname>'
+    }
+
+    def rendersLinkToExternalClass() {
+        when:
+        def link = renderer.link(type('some.other.Class'), listener)
+
+        then:
+        format(link) == '<classname>some.other.Class</classname>'
+    }
+
+    def rendersLinkToExternalClassArray() {
+        when:
+        def link = renderer.link(type('some.other.Class', true), listener)
+
+        then:
+        format(link) == '<classname><classname>some.other.Class</classname>[]</classname>'
+    }
+
+    def rendersLinkToParameterizedType() {
+        def metaData = type('org.gradle.SomeClass')
+        metaData.addTypeArg(type('Type1'))
+        metaData.addTypeArg(type('Type2'))
+
+        when:
+        def link = renderer.link(metaData, listener)
+
+        then:
+        format(link) == '<classname><apilink class="org.gradle.SomeClass"/><<apilink class="Type1"/>, <apilink class="Type2"/>></classname>'
+        _ * model.isKnownType('org.gradle.SomeClass') >> true
+        _ * model.isKnownType('Type1') >> true
+        _ * model.isKnownType('Type2') >> true
+    }
+
+    def rendersLinkToApiMethod() {
+        def method = method('someMethod', 'org.gradle.SomeClass')
+
+        when:
+        def link = renderer.link(method, listener)
+
+        then:
+        format(link) == '<apilink class="org.gradle.SomeClass" method="someMethod()"/>'
+        _ * model.isKnownType('org.gradle.SomeClass') >> true
+    }
+
+    def method(String name, String className) {
+        MethodMetaData method = Mock()
+        ClassMetaData ownerClass = Mock()
+        _ * method.name >> name
+        _ * method.overrideSignature >> "$name()"
+        _ * method.ownerClass >> ownerClass
+        _ * ownerClass.className >> className
+        return method
+    }
+
+    def type(String name, boolean isArray = false) {
+        TypeMetaData type = new TypeMetaData(name)
+        if (isArray) {
+            type.addArrayDimension()
+        }
+        return type
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/MethodMetaDataTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/MethodMetaDataTest.groovy
new file mode 100644
index 0000000..5d31ba7
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/MethodMetaDataTest.groovy
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model
+
+import spock.lang.Specification
+
+class MethodMetaDataTest extends Specification {
+    final ClassMetaData owner = Mock()
+    final MethodMetaData method = new MethodMetaData('method', owner)
+
+    def formatsSignature() {
+        method.returnType = new TypeMetaData('ReturnType')
+        method.addParameter('param1', new TypeMetaData('ParamType'))
+        method.addParameter('param2', new TypeMetaData('ParamType2'))
+
+        expect:
+        method.signature == 'ReturnType method(ParamType param1, ParamType2 param2)'
+    }
+
+    def formatsOverrideSignatureUsingRawParameterTypes() {
+        method.returnType = new TypeMetaData('ReturnType')
+        method.addParameter('param', new TypeMetaData('ParamType').addTypeArg(new TypeMetaData("Type1")))
+        method.addParameter('param2', new TypeMetaData('ParamType2'))
+
+        expect:
+        method.overrideSignature == 'method(ParamType, ParamType2)'
+    }
+
+    def locatesOverriddenMethodInSuperClass() {
+        ClassMetaData superClassMetaData = Mock()
+        MethodMetaData overriddenMethod = Mock()
+
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == overriddenMethod
+        _ * owner.superClass >> superClassMetaData
+        _ * owner.interfaces >> []
+        1 * superClassMetaData.findDeclaredMethod('method()') >> overriddenMethod
+    }
+
+    def locatesOverriddenMethodInDirectlyImplementedInterface() {
+        ClassMetaData interfaceMetaData = Mock()
+        MethodMetaData overriddenMethod = Mock()
+
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == overriddenMethod
+        _ * owner.superClass >> null
+        _ * owner.interfaces >> [interfaceMetaData]
+        1 * interfaceMetaData.findDeclaredMethod('method()') >> overriddenMethod
+    }
+
+    def locatesOverriddenMethodInAncestorClass() {
+        ClassMetaData superClassMetaData = Mock()
+        ClassMetaData ancestorClassMetaData = Mock()
+        MethodMetaData overriddenMethod = Mock()
+
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == overriddenMethod
+        _ * owner.superClass >> superClassMetaData
+        _ * owner.interfaces >> []
+        1 * superClassMetaData.findDeclaredMethod('method()') >> null
+        _ * superClassMetaData.superClass >> ancestorClassMetaData
+        _ * superClassMetaData.interfaces >> []
+        1 * ancestorClassMetaData.findDeclaredMethod('method()') >> overriddenMethod
+    }
+
+    def locatesOverriddenMethodInInterfaceOfAncestorClass() {
+        ClassMetaData superClassMetaData = Mock()
+        ClassMetaData interfaceMetaData = Mock()
+        MethodMetaData overriddenMethod = Mock()
+
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == overriddenMethod
+        _ * owner.superClass >> superClassMetaData
+        _ * owner.interfaces >> []
+        1 * superClassMetaData.findDeclaredMethod('method()') >> null
+        _ * superClassMetaData.superClass >> null
+        _ * superClassMetaData.interfaces >> [interfaceMetaData]
+        1 * interfaceMetaData.findDeclaredMethod('method()') >> overriddenMethod
+    }
+
+    def hasNoOverriddenMethodWhenNoSuperClass() {
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == null
+        _ * owner.superClass >> null
+        _ * owner.interfaces >> []
+    }
+
+    def hasNoOverriddenMethodWhenMethodDoesNotOverrideMethodInSuperClass() {
+        ClassMetaData superClassMetaData = Mock()
+
+        when:
+        def m = method.overriddenMethod
+
+        then:
+        m == null
+        _ * owner.superClass >> superClassMetaData
+        _ * owner.interfaces >> []
+        1 * superClassMetaData.findDeclaredMethod('method()') >> null
+        _ * superClassMetaData.superClass >> null
+        _ * superClassMetaData.interfaces >> []
+    }
+}
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/ParameterMetaDataTest.groovy
similarity index 57%
rename from buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
rename to buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/ParameterMetaDataTest.groovy
index a1681cf..16ef3a6 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/dsl/PropertyMetaData.java
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/ParameterMetaDataTest.groovy
@@ -13,27 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.build.docs.dsl;
+package org.gradle.build.docs.dsl.model
 
-import java.io.Serializable;
+import spock.lang.Specification
 
-public class PropertyMetaData implements Serializable {
-    private String type;
-    private boolean writeable;
+class ParameterMetaDataTest extends Specification {
+    final MethodMetaData method = Mock()
+    final ParameterMetaData parameter = new ParameterMetaData('param', method)
 
-    public String getType() {
-        return type;
-    }
-
-    public void setType(String type) {
-        this.type = type;
-    }
-
-    public boolean isWriteable() {
-        return writeable;
-    }
-
-    public void setWriteable(boolean writeable) {
-        this.writeable = writeable;
+    def formatsSignature() {
+        def type = new TypeMetaData('org.gradle.SomeType')
+        parameter.type = type
+        
+        expect:
+        parameter.signature == 'org.gradle.SomeType param'
     }
 }
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/PropertyMetaDataTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/PropertyMetaDataTest.groovy
new file mode 100644
index 0000000..9d655b1
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/PropertyMetaDataTest.groovy
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model
+
+import spock.lang.Specification
+
+class PropertyMetaDataTest extends Specification {
+    final ClassMetaData classMetaData = Mock()
+    final PropertyMetaData propertyMetaData = new PropertyMetaData('prop', classMetaData)
+
+    def formatsSignature() {
+        def type = new TypeMetaData('org.gradle.SomeClass')
+        propertyMetaData.type = type
+
+        expect:
+        propertyMetaData.signature == 'org.gradle.SomeClass prop'
+    }
+
+    def usesGetterToLocateOverriddenProperty() {
+        MethodMetaData getter = Mock()
+        MethodMetaData overriddenGetter = Mock()
+        ClassMetaData overriddenClass = Mock()
+        PropertyMetaData overriddenProperty = Mock()
+        propertyMetaData.getter = getter
+
+        when:
+        def p = propertyMetaData.overriddenProperty
+
+        then:
+        p == overriddenProperty
+        _ * getter.overriddenMethod >> overriddenGetter
+        _ * overriddenGetter.ownerClass >> overriddenClass
+        _ * overriddenClass.findDeclaredProperty('prop') >> overriddenProperty
+    }
+
+    def usesSetterToLocateOverriddenPropertyWhenPropertyHasNoGetter() {
+        MethodMetaData setter = Mock()
+        MethodMetaData overriddenSetter = Mock()
+        ClassMetaData overriddenClass = Mock()
+        PropertyMetaData overriddenProperty = Mock()
+        propertyMetaData.setter = setter
+
+        when:
+        def p = propertyMetaData.overriddenProperty
+
+        then:
+        p == overriddenProperty
+        _ * setter.overriddenMethod >> overriddenSetter
+        _ * overriddenSetter.ownerClass >> overriddenClass
+        _ * overriddenClass.findDeclaredProperty('prop') >> overriddenProperty
+    }
+
+    def usesSetterToLocateOverriddenPropertyWhenGetterDoesNotOverrideAnything() {
+        MethodMetaData getter = Mock()
+        MethodMetaData setter = Mock()
+        MethodMetaData overriddenSetter = Mock()
+        ClassMetaData overriddenClass = Mock()
+        PropertyMetaData overriddenProperty = Mock()
+        propertyMetaData.getter = getter
+        propertyMetaData.setter = setter
+
+        when:
+        def p = propertyMetaData.overriddenProperty
+
+        then:
+        p == overriddenProperty
+        1 * getter.overriddenMethod >> null
+        _ * setter.overriddenMethod >> overriddenSetter
+        _ * overriddenSetter.ownerClass >> overriddenClass
+        _ * overriddenClass.findDeclaredProperty('prop') >> overriddenProperty
+    }
+
+    def hasNoOverriddenPropertyWhenGetterDoesNotOverrideAnythingAndHasNoSetter() {
+        when:
+        def p = propertyMetaData.overriddenProperty
+
+        then:
+        p == null
+    }
+
+    def hasNoOverriddenPropertyWhenGetterAndSetterDoNotOverrideAnything() {
+        when:
+        def p = propertyMetaData.overriddenProperty
+
+        then:
+        p == null
+    }
+}
+
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/TypeMetaDataTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/TypeMetaDataTest.groovy
new file mode 100644
index 0000000..76aaa23
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/model/TypeMetaDataTest.groovy
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.dsl.model
+
+import spock.lang.Specification
+
+class TypeMetaDataTest extends Specification {
+    final TypeMetaData type = new TypeMetaData('org.gradle.SomeType')
+
+    def rawTypeForSimpleType() {
+        expect:
+        type.rawType.signature == 'org.gradle.SomeType'
+    }
+
+    def rawTypeForArrayType() {
+        type.addArrayDimension()
+        type.addArrayDimension()
+
+        expect:
+        type.rawType.signature == 'org.gradle.SomeType[][]'
+    }
+
+    def rawTypeForVarargsType() {
+        type.setVarargs()
+
+        expect:
+        type.rawType.signature == 'org.gradle.SomeType...'
+    }
+
+    def rawTypeForParameterizedArrayType() {
+        type.addArrayDimension()
+        type.addArrayDimension()
+        type.addTypeArg(new TypeMetaData('Type1'))
+
+        expect:
+        type.rawType.signature == 'org.gradle.SomeType[][]'
+    }
+
+    def rawTypeForParameterizedType() {
+        type.addTypeArg(new TypeMetaData('Type1'))
+        type.addTypeArg(new TypeMetaData('Type2'))
+
+        expect:
+        type.rawType.signature == 'org.gradle.SomeType'
+    }
+
+    def rawTypeForWildcardType() {
+        type.setWildcard()
+
+        expect:
+        type.rawType.signature == 'java.lang.Object'
+    }
+
+    def rawTypeForWildcardWithUpperBound() {
+        type.setUpperBounds(new TypeMetaData('OtherType'))
+
+        expect:
+        type.rawType.signature == 'OtherType'
+    }
+
+    def rawTypeForWildcardWithLowerBound() {
+        type.setLowerBounds(new TypeMetaData('OtherType'))
+
+        expect:
+        type.rawType.signature == 'java.lang.Object'
+    }
+
+    def formatsSignature() {
+        expect:
+        type.signature == 'org.gradle.SomeType'
+    }
+
+    def formatsSignatureForArrayType() {
+        type.addArrayDimension()
+        type.addArrayDimension()
+
+        expect:
+        type.signature == 'org.gradle.SomeType[][]'
+    }
+
+    def formatsSignatureForArrayAndVarargsType() {
+        type.addArrayDimension()
+        type.addArrayDimension()
+        type.setVarargs()
+
+        expect:
+        type.signature == 'org.gradle.SomeType[][]...'
+    }
+
+    def formatsSignatureForParameterizedType() {
+        type.addTypeArg(new TypeMetaData('Type1'))
+        type.addTypeArg(new TypeMetaData('Type2'))
+
+        expect:
+        type.signature == 'org.gradle.SomeType<Type1, Type2>'
+    }
+
+    def formatsSignatureForWildcardType() {
+        type.setWildcard()
+
+        expect:
+        type.signature == '?'
+    }
+
+    def formatsSignatureForWildcardWithUpperBound() {
+        type.setUpperBounds(new TypeMetaData('OtherType'))
+
+        expect:
+        type.signature == '? extends OtherType'
+    }
+
+    def formatsSignatureForWildcardWithLowerBound() {
+        type.setLowerBounds(new TypeMetaData('OtherType'))
+
+        expect:
+        type.signature == '? super OtherType'
+    }
+
+    def visitsSignature() {
+        TypeMetaData.SignatureVisitor visitor = Mock()
+
+        when:
+        type.visitSignature(visitor)
+
+        then:
+        1 * visitor.visitType('org.gradle.SomeType')
+        0 * visitor._
+    }
+
+    def visitsSignatureForArrayType() {
+        TypeMetaData.SignatureVisitor visitor = Mock()
+        type.addArrayDimension()
+        type.addArrayDimension()
+
+        when:
+        type.visitSignature(visitor)
+
+        then:
+        1 * visitor.visitType('org.gradle.SomeType')
+        1 * visitor.visitText('[][]')
+        0 * visitor._
+    }
+
+    def visitsSignatureForParameterizedType() {
+        TypeMetaData.SignatureVisitor visitor = Mock()
+        type.addTypeArg(new TypeMetaData('OtherType'))
+
+        when:
+        type.visitSignature(visitor)
+
+        then:
+        1 * visitor.visitType('org.gradle.SomeType')
+        1 * visitor.visitText('<')
+        1 * visitor.visitType('OtherType')
+        1 * visitor.visitText('>')
+        0 * visitor._
+    }
+
+    def visitsSignatureForWildcardType() {
+        TypeMetaData.SignatureVisitor visitor = Mock()
+        type.setWildcard()
+
+        when:
+        type.visitSignature(visitor)
+
+        then:
+        1 * visitor.visitText('?')
+        0 * visitor._
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepositoryTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepositoryTest.groovy
new file mode 100644
index 0000000..23e867b
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/model/SimpleClassMetaDataRepositoryTest.groovy
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2010 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 org.gradle.build.docs.model
+
+import spock.lang.Specification
+import org.gradle.api.UnknownDomainObjectException
+
+class SimpleClassMetaDataRepositoryTest extends Specification {
+    final SimpleClassMetaDataRepository<TestDomainObject> repository = new SimpleClassMetaDataRepository<TestDomainObject>()
+
+    def canAddMetaData() {
+        TestDomainObject value = new TestDomainObject('a')
+
+        when:
+        repository.put('class', value)
+
+        then:
+        repository.find('class') == value
+        repository.get('class') == value
+    }
+
+    def findReturnsNullForUnknownClass() {
+        expect:
+        repository.find('unknown') == null
+    }
+
+    def getFailsForUnknownClass() {
+        when:
+        repository.get('unknown')
+
+        then:
+        UnknownDomainObjectException e = thrown()
+        e.message == 'No meta-data is available for class \'unknown\'.'
+    }
+
+    def canIterateOverClasses() {
+        TestDomainObject value1 = new TestDomainObject('a')
+        TestDomainObject value2 = new TestDomainObject('a')
+        repository.put('class1', value1)
+        repository.put('class2', value2)
+        Closure cl = Mock()
+
+        when:
+        repository.each(cl)
+
+        then:
+        1 * cl.call(['class1', value1] as Object[])
+        1 * cl.call(['class2', value2] as Object[])
+        0 * cl._
+    }
+
+    def canPersistMetaData() {
+        TestDomainObject value = new TestDomainObject('a')
+        File file = File.createTempFile("test-repository", "bin")
+        repository.put('class', value)
+
+        when:
+        repository.store(file)
+        def newRepo = new SimpleClassMetaDataRepository<String>()
+        newRepo.load(file)
+
+        then:
+        newRepo.find('class') == value
+    }
+}
+
+class TestDomainObject implements Attachable<TestDomainObject>, Serializable {
+    def value
+
+    TestDomainObject(String value) {
+        this.value = value
+    }
+
+    @Override
+    boolean equals(Object o) {
+        return o.value == value
+    }
+
+    @Override
+    int hashCode() {
+        return value.hashCode()
+    }
+
+    void attach(ClassMetaDataRepository<TestDomainObject> repository) {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/A.groovy b/buildSrc/src/test/resources/org/gradle/test/A.groovy
new file mode 100644
index 0000000..90b27b5
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/A.groovy
@@ -0,0 +1,4 @@
+package org.gradle.test
+
+class A {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyAnnotation.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyAnnotation.groovy
new file mode 100644
index 0000000..6db3075
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyAnnotation.groovy
@@ -0,0 +1,5 @@
+package org.gradle.test
+
+public @interface GroovyAnnotation {
+
+}
\ No newline at end of file
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClass.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClass.groovy
new file mode 100644
index 0000000..cbb8707
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClass.groovy
@@ -0,0 +1,55 @@
+package org.gradle.test
+
+/**
+ * This is a groovy class.
+ */
+class GroovyClass extends A implements GroovyInterface, JavaInterface {
+    /**
+     * A groovy property.
+     */
+    GroovyInterface groovyProp
+
+    /**
+     * A read-only groovy property.
+     */
+    final String readOnlyGroovyProp
+
+    /**
+     * An array property.
+     */
+    def String[] arrayProp
+
+    private def ignoreMe1;
+    public int ignoreMe2;
+    protected int ignoreMe3;
+    static String ignoreMe4;
+
+    /**
+     * A read-only property.
+     */
+    def getReadOnly() {
+        'value'
+    }
+
+    /**
+     * A property.
+     */
+    GroovyInterface getSomeProp() {
+        this
+    }
+
+    void setSomeProp(GroovyInterface value) {
+    }
+
+    /**
+     * A write-only property.
+     */
+    void setWriteOnly(JavaInterface value) {
+    }
+
+    public void setIgnoreMe1() {
+    }
+
+    public void setIgnoreMe2(String a, int b) {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithConstants.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithConstants.groovy
new file mode 100644
index 0000000..0319d10
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithConstants.groovy
@@ -0,0 +1,12 @@
+package org.gradle.test
+
+class GroovyClassWithConstants {
+    static final int INT_CONST = 9
+    public static final String STRING_CONST = 'some-string'
+    static final Object OBJECT_CONST = new GroovyClassWithConstants()
+    static final def BIG_DECIMAL_CONST = 1.02
+
+    String ignored = 'ignore'
+    final int ignored2 = 1001
+    static def ignored3
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithFullyQualifiedNames.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithFullyQualifiedNames.groovy
new file mode 100644
index 0000000..73654a9
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithFullyQualifiedNames.groovy
@@ -0,0 +1,10 @@
+package org.gradle.test
+
+class GroovyClassWithFullyQualifiedNames extends org.gradle.test.sub.SubGroovyClass implements org.gradle.test.sub.SubJavaInterface, java.lang.Runnable {
+    org.gradle.test.sub.SubJavaInterface getProp() {
+        this
+    }
+
+    void run() {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithImports.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithImports.groovy
new file mode 100644
index 0000000..345f5d0
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithImports.groovy
@@ -0,0 +1,10 @@
+package org.gradle.test
+
+import org.gradle.test.sub.*;
+
+class GroovyClassWithImports extends SubGroovyClass implements SubJavaInterface, GroovyInterface {
+    void close() {
+    }
+}
+
+import org.gradle.test.sub2.GroovyInterface;
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithInnerTypes.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithInnerTypes.groovy
new file mode 100644
index 0000000..1e1f324
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithInnerTypes.groovy
@@ -0,0 +1,31 @@
+package org.gradle.test
+
+import org.gradle.test.sub2.GroovyInterface
+
+class GroovyClassWithInnerTypes implements GroovyInterface {
+    /**
+     * This is an inner enum.
+     */
+    enum InnerEnum {}
+
+    /**
+     * This is an inner class.
+     */
+    static class InnerClass {
+        InnerEnum enumProp
+
+        /**
+         * This is an inner inner class.
+         */
+        class AnotherInner {
+            InnerClass outer
+        }
+    }
+
+    GroovyInterface getSomeProp() {
+        // ignore anonymous classes
+        return new GroovyInterface() {}
+    }
+
+    InnerClass.AnotherInner innerClassProp
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithMethods.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithMethods.groovy
new file mode 100644
index 0000000..490fa76
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithMethods.groovy
@@ -0,0 +1,57 @@
+package org.gradle.test
+
+class GroovyClassWithMethods {
+
+    GroovyClassWithMethods(String prop) {
+        this.prop = prop
+    }
+
+    /**
+     * A method that returns String.
+     */
+    String stringMethod(String stringParam) {
+        'value'
+    }
+
+    /**
+     * A method that returns void.
+     */
+    void voidMethod() {
+    }
+
+    /**
+     * A method that returns a reference type.
+     */
+    public final GroovyInterface refTypeMethod(JavaInterface someThing, boolean aFlag) {
+        null
+    }
+
+    /**
+     * A method that returns a default type.
+     */
+    def defMethod(def defParam) {
+        null
+    }
+
+    /**
+     * A method that returns an array
+     */
+    String[][] arrayMethod(String[]... strings) {
+        null
+    }
+
+    /**
+     * A String property.
+     */
+    String prop
+
+    /**
+     * A read-only property.
+     */
+    final JavaInterface finalProp
+
+    int getIntProp() { 5 }
+
+    void setIntProp(int prop) { }
+}
+
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithParameterizedTypes.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithParameterizedTypes.groovy
new file mode 100644
index 0000000..f11f51a
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyClassWithParameterizedTypes.groovy
@@ -0,0 +1,19 @@
+package org.gradle.test
+
+class GroovyClassWithParameterizedTypes {
+    Set<GroovyInterface> setProp
+
+    Map<GroovyInterface, GroovyClassWithParameterizedTypes> mapProp
+
+    List<?> wildcardProp
+
+    List<? extends GroovyInterface> upperBoundProp
+
+    List<? super GroovyInterface> lowerBoundProp
+
+    List<? super Set<? extends Map<?, GroovyInterface[]>>>[] nestedProp
+
+    static <T> T paramMethod(T param) {
+        null
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyEnum.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyEnum.groovy
new file mode 100644
index 0000000..b0eb5be
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyEnum.groovy
@@ -0,0 +1,5 @@
+package org.gradle.test
+
+public enum GroovyEnum {
+    A, B
+}
\ No newline at end of file
diff --git a/buildSrc/src/test/resources/org/gradle/test/GroovyInterface.groovy b/buildSrc/src/test/resources/org/gradle/test/GroovyInterface.groovy
new file mode 100644
index 0000000..ce6168d
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/GroovyInterface.groovy
@@ -0,0 +1,4 @@
+package org.gradle.test
+
+public interface GroovyInterface extends Interface1, Interface2 {
+}
\ No newline at end of file
diff --git a/buildSrc/src/test/resources/org/gradle/test/Interface1.java b/buildSrc/src/test/resources/org/gradle/test/Interface1.java
new file mode 100644
index 0000000..823fe13
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/Interface1.java
@@ -0,0 +1,4 @@
+package org.gradle.test;
+
+public interface Interface1 {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/Interface2.groovy b/buildSrc/src/test/resources/org/gradle/test/Interface2.groovy
new file mode 100644
index 0000000..be6a7cc
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/Interface2.groovy
@@ -0,0 +1,5 @@
+package org.gradle.test
+
+public interface Interface2 {
+
+}
\ No newline at end of file
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaAnnotation.java b/buildSrc/src/test/resources/org/gradle/test/JavaAnnotation.java
new file mode 100644
index 0000000..f206158
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaAnnotation.java
@@ -0,0 +1,4 @@
+package org.gradle.test;
+
+public @interface JavaAnnotation {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClass.java b/buildSrc/src/test/resources/org/gradle/test/JavaClass.java
new file mode 100644
index 0000000..9b33f5b
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClass.java
@@ -0,0 +1,69 @@
+package org.gradle.test;
+
+/**
+ * This is a java class.
+ */
+public class JavaClass extends A implements GroovyInterface, JavaInterface {
+    /**
+     * A read-only property.
+     */
+    public String getReadOnly() {
+        return "value";
+    }
+
+    /**
+     * An ignored field.
+     */
+    String ignoreMe1;
+
+    /**
+     * Another ignored field.
+     */
+    final long ignoreMe2 = 9;
+
+    /**
+     * Not a setter.
+     */
+    public void setIgnoreMe1() {
+    }
+
+    /**
+     * Not a setter.
+     */
+    public void setIgnoreMe2(String a, int b) {
+    }
+
+    /**
+     * A write-only property.
+     */
+    public void setWriteOnly(JavaInterface value) {
+    }
+
+    /**
+     * A property.
+     */
+    public JavaInterface getSomeProp() {
+        return this;
+    }
+
+    /**
+     * The setter for a property.
+     * @param value
+     */
+    public void setSomeProp(JavaInterface value) {
+    }
+
+    /**
+     * A boolean property.
+     */
+    boolean isFlag() {
+        return false;
+    }
+
+    /**
+     * An array property.
+     */
+    public JavaInterface[][][] getArrayProp() {
+        return null;
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithConstants.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithConstants.java
new file mode 100644
index 0000000..0261a3c
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithConstants.java
@@ -0,0 +1,11 @@
+package org.gradle.test;
+
+public class JavaClassWithConstants {
+    public static final String STRING_CONST = "some-string";
+    static final char CHAR_CONST = 'a';
+    static final int INT_CONST = 9;
+    protected static final Object OBJECT_CONST = new JavaClassWithConstants();
+
+    static String ignored = "ignore";
+    String ignored2 = "ignore";
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithFullyQualifiedNames.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithFullyQualifiedNames.java
new file mode 100644
index 0000000..4b66b07
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithFullyQualifiedNames.java
@@ -0,0 +1,10 @@
+package org.gradle.test;
+
+public class JavaClassWithFullyQualifiedNames extends org.gradle.test.sub.SubGroovyClass implements org.gradle.test.sub.SubJavaInterface, java.lang.Runnable {
+    org.gradle.test.sub.SubJavaInterface getProp() {
+        return this;
+    }
+
+    public void run() {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithImports.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithImports.java
new file mode 100644
index 0000000..614d10e
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithImports.java
@@ -0,0 +1,12 @@
+package org.gradle.test;
+
+import org.gradle.test.sub.*;
+import org.gradle.test.sub2.GroovyInterface;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public class JavaClassWithImports extends SubGroovyClass implements SubJavaInterface, GroovyInterface, Closeable {
+    public void close() throws IOException {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithInnerTypes.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithInnerTypes.java
new file mode 100644
index 0000000..e97ce52
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithInnerTypes.java
@@ -0,0 +1,41 @@
+package org.gradle.test;
+
+import org.gradle.test.sub2.GroovyInterface;
+
+public class JavaClassWithInnerTypes implements GroovyInterface {
+    /**
+     * This is an inner enum.
+     */
+    enum InnerEnum {
+    }
+
+    /**
+     * This is an inner class.
+     */
+    static class InnerClass {
+        InnerEnum getEnumProp() { return null; }
+
+        /**
+         * This is an inner inner class.
+         */
+        class AnotherInner {
+            InnerClass getOuter() { return null; }
+        }
+    }
+
+    GroovyInterface getSomeProp() {
+        // ignore classes in method bodies
+        class IgnoreMe {}
+
+        // ignore anonymous classes
+        return new GroovyInterface() { };
+    }
+
+    // ignore anonymous classes
+    final Runnable ignoreMe = new Runnable() {
+        public void run() {
+        }
+    };
+
+    InnerClass.AnotherInner getInnerClassProp() { return null; }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithMethods.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithMethods.java
new file mode 100644
index 0000000..0420004
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithMethods.java
@@ -0,0 +1,40 @@
+package org.gradle.test;
+
+public class JavaClassWithMethods {
+    public JavaClassWithMethods(String value) {
+    }
+
+    /**
+     * A method that returns String.
+     */
+    String stringMethod(String stringParam) {
+        return "value";
+    }
+
+    /**
+     * A method that returns void.
+     */
+    void voidMethod() {
+    }
+
+    /**
+     * A method that returns a reference type.
+     */
+    GroovyInterface refTypeMethod(JavaInterface refParam, boolean aFlag) {
+        return null;
+    }
+
+    /**
+     * A method that returns an array
+     */
+    String[][] arrayMethod(String[]... strings) {
+        return null;
+    }
+
+    int getIntProp() {
+        return 5;
+    }
+
+    void setIntProp(int prop) {
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaClassWithParameterizedTypes.java b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithParameterizedTypes.java
new file mode 100644
index 0000000..9f47557
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaClassWithParameterizedTypes.java
@@ -0,0 +1,21 @@
+package org.gradle.test;
+
+import java.util.*;
+
+public class JavaClassWithParameterizedTypes {
+    Set<GroovyInterface> getSetProp() { return null; }
+
+    Map<GroovyInterface, JavaClassWithParameterizedTypes> getMapProp() { return null; }
+
+    List<?> getWildcardProp() { return null; }
+
+    List<? extends GroovyInterface> getUpperBoundProp() { return null; }
+
+    List<? super GroovyInterface> getLowerBoundProp() { return null; }
+
+    List<? super Set<? extends Map<?, GroovyInterface[]>>>[] getNestedProp() { return null; }
+
+    <T extends JavaInterface> T paramMethod(T param) {
+        return null;
+    }
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaEnum.java b/buildSrc/src/test/resources/org/gradle/test/JavaEnum.java
new file mode 100644
index 0000000..2d25146
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaEnum.java
@@ -0,0 +1,5 @@
+package org.gradle.test;
+
+public enum JavaEnum {
+    A, B
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaInterface.java b/buildSrc/src/test/resources/org/gradle/test/JavaInterface.java
new file mode 100644
index 0000000..c88a81d
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaInterface.java
@@ -0,0 +1,4 @@
+package org.gradle.test;
+
+public interface JavaInterface extends Interface1, Interface2 {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/JavaInterfaceWithConstants.java b/buildSrc/src/test/resources/org/gradle/test/JavaInterfaceWithConstants.java
new file mode 100644
index 0000000..f5773d3
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/JavaInterfaceWithConstants.java
@@ -0,0 +1,6 @@
+package org.gradle.test;
+
+public interface JavaInterfaceWithConstants {
+    String STRING_CONST = "some-string";
+    public static final int INT_CONST = 120;
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/sub/SubGroovyClass.groovy b/buildSrc/src/test/resources/org/gradle/test/sub/SubGroovyClass.groovy
new file mode 100644
index 0000000..dd41552
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/sub/SubGroovyClass.groovy
@@ -0,0 +1,4 @@
+package org.gradle.test.sub
+
+class SubGroovyClass {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/sub/SubJavaInterface.java b/buildSrc/src/test/resources/org/gradle/test/sub/SubJavaInterface.java
new file mode 100644
index 0000000..35b3d24
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/sub/SubJavaInterface.java
@@ -0,0 +1,4 @@
+package org.gradle.test.sub;
+
+public interface SubJavaInterface {
+}
diff --git a/buildSrc/src/test/resources/org/gradle/test/sub2/GroovyInterface.groovy b/buildSrc/src/test/resources/org/gradle/test/sub2/GroovyInterface.groovy
new file mode 100644
index 0000000..184d0e9
--- /dev/null
+++ b/buildSrc/src/test/resources/org/gradle/test/sub2/GroovyInterface.groovy
@@ -0,0 +1,5 @@
+package org.gradle.test.sub2
+
+public interface GroovyInterface {
+
+}
\ No newline at end of file
diff --git a/config/codenarc.xml b/config/codenarc.xml
index bc0586c..1e316e8 100644
--- a/config/codenarc.xml
+++ b/config/codenarc.xml
@@ -16,6 +16,11 @@
 <ruleset xmlns="http://codenarc.org/ruleset/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://codenarc.org/ruleset/1.0 http://codenarc.org/ruleset-schema.xsd"
          xsi:noNamespaceSchemaLocation="http://codenarc.org/ruleset-schema.xsd">
+    <!--<ruleset-ref path='rulesets/basic.xml'>-->
+        <!--<exclude name='ExplicitHashSetInstantiation'/>-->
+        <!--<exclude name='ExplicitCallToAndMethod'/>-->
+        <!--<exclude name='ExplicitCallToOrMethod'/>-->
+    <!--</ruleset-ref>-->
     <ruleset-ref path='rulesets/braces.xml'/>
     <ruleset-ref path='rulesets/imports.xml'/>
     <ruleset-ref path='rulesets/naming.xml'>
diff --git a/gradle.properties b/gradle.properties
index f426a85..8bfd5f2 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,2 @@
-previousVersion=0.9-rc-2
-nextVersion=0.9-rc-3
+previousVersion=0.9-rc-3
+nextVersion=0.9
diff --git a/gradle/codeQuality.gradle b/gradle/codeQuality.gradle
new file mode 100644
index 0000000..093ea87
--- /dev/null
+++ b/gradle/codeQuality.gradle
@@ -0,0 +1,19 @@
+apply plugin: 'code-quality'
+
+def configDir = new File(buildscript.sourceFile.parentFile.parentFile, 'config')
+
+checkstyleConfigDir = "$configDir/checkstyle"
+checkstyleConfigFileName = new File(checkstyleConfigDir, "checkstyle.xml")
+codeNarcConfigFileName = "$configDir/codenarc.xml"
+checkstyleProperties.checkstyleConfigDir = checkstyleConfigDir
+
+plugins.withType(GroovyBasePlugin).allObjects {
+    sourceSets.allObjects { sourceSet ->
+        task "${sourceSet.getTaskName('checkstyle', 'groovy')}"(type: Checkstyle) {
+            configFile = new File(checkstyleConfigDir, "checkstyle-groovy.xml")
+            source sourceSet.allGroovy
+            classpath = sourceSet.compileClasspath
+            resultFile = new File(checkstyleResultsDir, "${sourceSet.name}-groovy.xml")
+        }
+    }
+}
diff --git a/src/toplevel/changelog.txt b/src/toplevel/changelog.txt
index db082b9..b31a4e1 100644
--- a/src/toplevel/changelog.txt
+++ b/src/toplevel/changelog.txt
@@ -1,4 +1,4 @@
 
-Release Notes - Gradle - Version 0.9-rc-3
+Release Notes - Gradle - Version 0.9
 
 See http://docs.codehaus.org/display/GRADLE/Gradle+0.9+Release+Notes
\ No newline at end of file
diff --git a/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/AnnouncePlugin.groovy b/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/AnnouncePlugin.groovy
index e254f77..205488b 100644
--- a/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/AnnouncePlugin.groovy
+++ b/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/AnnouncePlugin.groovy
@@ -34,8 +34,16 @@ class AnnouncePlugin implements Plugin<Project> {
 }
 
 class AnnouncePluginConvention {
+    /**
+     * The username to use for announcements
+     */
     String username
+
+    /**
+     * The password to use for announcements
+     */
     String password
+
     Project project
     AnnouncerFactory announcerFactory
 
@@ -44,11 +52,19 @@ class AnnouncePluginConvention {
         this.announcerFactory = new DefaultAnnouncerFactory(this)
     }
 
+    /**
+     * Configures the announce plugin convention. The given closure configures the {@link AnnouncePluginConvention}.
+     */
     def announce(Closure closure) {
         closure.delegate = this
         closure()
     }
 
+    /**
+     * Sends an announcement of the given type.
+     * @param msg The content of the announcement
+     * @param type The announcement type.
+     */
     def announce(String msg, def type) {
         announcerFactory.createAnnouncer(type).send(project.name, msg)
     }
diff --git a/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/internal/Snarl.groovy b/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/internal/Snarl.groovy
index e5d9224..37d24c9 100644
--- a/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/internal/Snarl.groovy
+++ b/subprojects/gradle-announce/src/main/groovy/org/gradle/api/plugins/announce/internal/Snarl.groovy
@@ -54,11 +54,11 @@ class Snarl implements Announcer {
   }
 
   private String formatProperty(String name, String value) {
-    if (!value) {
-      return ""
+    if (value) {
+      return "#?" + name + "=" + value
     }
     else {
-      return "#?" + name + "=" + value
+      return ""
     }
   }
 
@@ -66,11 +66,7 @@ class Snarl implements Announcer {
     try {
       closure(closable)
     } finally {
-      try {
-        closable.close()
-      } catch (Exception e) {
-
-      }
+      closable.close()
     }
   }
 }
diff --git a/subprojects/gradle-antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java b/subprojects/gradle-antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
index 2c4deb3..a639551 100644
--- a/subprojects/gradle-antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
+++ b/subprojects/gradle-antlr/src/main/groovy/org/gradle/api/plugins/antlr/AntlrTask.java
@@ -34,7 +34,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * <p>Generates parsers from Antlr grammars.  Wrapper around the Ant {@link ANTLR} task.</p>
+ * <p>Generates parsers from Antlr grammars.</p>
  *
  * <p>Most properties here are self-evident, but I wanted to highlight one in particular: {@link #setAntlrClasspath} is
  * used to define the classpath that should be passed along to the Ant {@link ANTLR} task as its classpath.  That is the
@@ -56,6 +56,9 @@ public class AntlrTask extends SourceTask {
 
     private File outputDirectory;
 
+    /**
+     * Specifies that all rules call {@code traceIn}/{@code traceOut}.
+     */
     public boolean isTrace() {
         return trace;
     }
@@ -64,6 +67,9 @@ public class AntlrTask extends SourceTask {
         this.trace = trace;
     }
 
+    /**
+     * Specifies that all lexer rules call {@code traceIn}/{@code traceOut}.
+     */
     public boolean isTraceLexer() {
         return traceLexer;
     }
@@ -72,6 +78,9 @@ public class AntlrTask extends SourceTask {
         this.traceLexer = traceLexer;
     }
 
+    /**
+     * Specifies that all parser rules call {@code traceIn}/{@code traceOut}.
+     */
     public boolean isTraceParser() {
         return traceParser;
     }
@@ -80,6 +89,9 @@ public class AntlrTask extends SourceTask {
         this.traceParser = traceParser;
     }
 
+    /**
+     * Specifies that all tree walker rules call {@code traceIn}/{@code traceOut}.
+     */
     public boolean isTraceTreeWalker() {
         return traceTreeWalker;
     }
@@ -88,20 +100,40 @@ public class AntlrTask extends SourceTask {
         this.traceTreeWalker = traceTreeWalker;
     }
 
+    /**
+     * Returns the directory to generate the parser source files into.
+     *
+     * @return The output directory.
+     */
     @OutputDirectory
     public File getOutputDirectory() {
         return outputDirectory;
     }
 
+    /**
+     * Specifies the directory to generate the parser source files into.
+     *
+     * @param outputDirectory The output directory. Must not be null.
+     */
     public void setOutputDirectory(File outputDirectory) {
         this.outputDirectory = outputDirectory;
     }
 
+    /**
+     * Returns the classpath containing the Ant ANTLR task implementation.
+     *
+     * @return The Ant task implementation classpath.
+     */
     @InputFiles
     public FileCollection getAntlrClasspath() {
         return antlrClasspath;
     }
 
+    /**
+     * Specifies the classpath containing the Ant ANTLR task implementation.
+     *
+     * @param antlrClasspath The Ant task implementation classpath. Must not be null.
+     */
     public void setAntlrClasspath(FileCollection antlrClasspath) {
         this.antlrClasspath = antlrClasspath;
     }
diff --git a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.java b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.java
index 4a11975..1789884 100644
--- a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.java
+++ b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/Checkstyle.java
@@ -43,33 +43,70 @@ public class Checkstyle extends SourceTask implements VerificationTask {
         antCheckstyle.checkstyle(getAnt(), getSource(), getConfigFile(), getResultFile(), getClasspath(), getProperties(), isIgnoreFailures());
     }
 
+    /**
+     * Returns the Checkstyle configuration file to use.
+     *
+     * @return The configuration file.
+     */
     @InputFile
     public File getConfigFile() {
         return configFile;
     }
 
+    /**
+     * Specifies the Checkstyle configuration file to use.
+     *
+     * @param configFile The configuration file. Must not be null.
+     */
     public void setConfigFile(File configFile) {
         this.configFile = configFile;
     }
 
+    /**
+     * Returns the file to generate the XML results to.
+     *
+     * @return The result XML file.
+     */
     @OutputFile
     public File getResultFile() {
         return resultFile;
     }
 
+    /**
+     * Specifies the file to generate the XML results to.
+     *
+     * @param resultFile The result XML file. Must not be null.
+     */
     public void setResultFile(File resultFile) {
         this.resultFile = resultFile;
     }
 
+    /**
+     * Returns the classpath containing the compiled classes for the source files to be inspected.
+     *
+     * @return The classpath.
+     */
     @InputFiles
     public FileCollection getClasspath() {
         return classpath;
     }
 
+    /**
+     * Specified the classpath containing the compiled classes for the source file to be inspected.
+     *
+     * @param classpath The classpath. Must not be null.
+     */
     public void setClasspath(FileCollection classpath) {
         this.classpath = classpath;
     }
 
+    /**
+     * Returns the properties available for use in the configuration file. These are substituted into the configuration
+     * file.
+     *
+     * @return The properties available in the configuration file. Returns an empty map when there are no such
+     *         properties.
+     */
     public Map<String, Object> getProperties() {
         return properties;
     }
diff --git a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/CodeNarc.java b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/CodeNarc.java
index f0bdc43..192b931 100644
--- a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/CodeNarc.java
+++ b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/CodeNarc.java
@@ -36,15 +36,30 @@ public class CodeNarc extends SourceTask implements VerificationTask {
         antCodeNarc.execute(getAnt(), getSource(), getConfigFile(), getReportFile(), isIgnoreFailures());
     }
 
+    /**
+     * Returns the CodeNarc configuration file to use.
+     *
+     * @return The CodeNarc configuration file.
+     */
     @InputFile
     public File getConfigFile() {
         return configFile;
     }
 
+    /**
+     * Specifies the CodeNarc configuration file to use.
+     *
+     * @param configFile The CodeNarc configuration file.
+     */
     public void setConfigFile(File configFile) {
         this.configFile = configFile;
     }
 
+    /**
+     * Returns the file to write the HTML report to.
+     *
+     * @return The HTML report file. Must not be null.
+     */
     @OutputFile
     public File getReportFile() {
         return reportFile;
diff --git a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/GroovyCodeQualityPluginConvention.groovy b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/GroovyCodeQualityPluginConvention.groovy
index 0097be9..96563d8 100644
--- a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/GroovyCodeQualityPluginConvention.groovy
+++ b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/GroovyCodeQualityPluginConvention.groovy
@@ -19,7 +19,14 @@ import org.gradle.api.Project
 import org.gradle.api.internal.project.ProjectInternal
 
 class GroovyCodeQualityPluginConvention {
+    /**
+     * The name of the CodeNarc configuration file, relative to the project directory.
+     */
     String codeNarcConfigFileName
+
+    /**
+     * The name of the directory to write CodeNarc reports into.
+     */
     String codeNarcReportsDirName
     private final ProjectInternal project
 
@@ -29,10 +36,16 @@ class GroovyCodeQualityPluginConvention {
         codeNarcReportsDirName = 'codenarc'
     }
 
+    /**
+     * The CodeNarc configuration file.
+     */
     File getCodeNarcConfigFile() {
         project.file(codeNarcConfigFileName)
     }
 
+    /**
+     * The directory to write CodeNarc reports into.
+     */
     File getCodeNarcReportsDir() {
         project.fileResolver.withBaseDir(project.reportsDir).resolve(codeNarcReportsDirName)
     }
diff --git a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/JavaCodeQualityPluginConvention.groovy b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/JavaCodeQualityPluginConvention.groovy
index 88bb31f..51c27ef 100644
--- a/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/JavaCodeQualityPluginConvention.groovy
+++ b/subprojects/gradle-code-quality/src/main/groovy/org/gradle/api/plugins/quality/JavaCodeQualityPluginConvention.groovy
@@ -19,9 +19,22 @@ import org.gradle.api.Project
 import org.gradle.api.internal.project.ProjectInternal
 
 class JavaCodeQualityPluginConvention {
+
+    /**
+     * The name of the Checkstyle configuration file, relative to the project directory.
+     */
     String checkstyleConfigFileName
+
+    /**
+     * The name of the directory to write Checkstyle results to, relative to the build directory.
+     */
     String checkstyleResultsDirName
+
+    /**
+     * The set of properties to substitute into the Checkstyle configuration file.
+     */
     Map<String, Object> checkstyleProperties = [:]
+
     private ProjectInternal project
 
     def JavaCodeQualityPluginConvention(Project project) {
@@ -30,10 +43,16 @@ class JavaCodeQualityPluginConvention {
         checkstyleResultsDirName = 'checkstyle'
     }
 
+    /**
+     * The Checkstyle configuration file.
+     */
     File getCheckstyleConfigFile() {
         project.file(checkstyleConfigFileName)
     }
 
+    /**
+     * The directory to write the Checkstyle results into.
+     */
     File getCheckstyleResultsDir() {
         project.fileResolver.withBaseDir(project.buildDir).resolve(checkstyleResultsDirName)
     }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
index 5330515..8773115 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
@@ -30,27 +30,30 @@ class CrossVersionCompatibilityIntegrationTest {
     private final BasicGradleDistribution gradle08 = dist.previousVersion('0.8')
     private final BasicGradleDistribution gradle09rc1 = dist.previousVersion('0.9-rc-1')
     private final BasicGradleDistribution gradle09rc2 = dist.previousVersion('0.9-rc-2')
+    private final BasicGradleDistribution gradle09rc3 = dist.previousVersion('0.9-rc-3')
 
     @Test
     public void canBuildJavaProject() {
         dist.testFile('buildSrc/src/main/groovy').assertIsDir()
 
-        // Upgrade and downgrade
-        eachVersion([gradle08, gradle09rc1, gradle09rc2, dist, gradle09rc2, gradle09rc1, gradle08]) { version ->
+        // Upgrade and downgrade from previous version to current version and back again
+        eachVersion([gradle08, gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
+            version.executer().inDirectory(dist.testDir).withTasks('build').run()
+            dist.executer().inDirectory(dist.testDir).withTasks('build').run()
             version.executer().inDirectory(dist.testDir).withTasks('build').run()
         }
     }
 
     @Test
     public void canUseWrapperFromPreviousVersionToRunCurrentVersion() {
-        eachVersion([gradle09rc1, gradle09rc2]) { version ->
+        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
             checkWrapperWorksWith(version, dist)
         }
     }
 
     @Test
     public void canUseWrapperFromCurrentVersionToRunPreviousVersion() {
-        eachVersion([gradle09rc1, gradle09rc2]) { version ->
+        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
             checkWrapperWorksWith(dist, version)
         }
     }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
index c83226a..e479148 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
@@ -54,6 +54,21 @@ public class JUnitIntegrationTest {
     }
 
     @Test
+    public void canRunJunit3Tests() {
+        executer.withTasks('check').withArguments('-PjunitVersion=4.8.1').run()
+
+        JUnitTestExecutionResult result = new JUnitTestExecutionResult(dist.testDir)
+        result.assertTestClassesExecuted('org.gradle.Test1')
+        result.testClass('org.gradle.Test1').assertTestPassed('testRenamesItself')
+
+        executer.withTasks('clean', 'check').withArguments('-PjunitVersion=3.8').run()
+
+        result = new JUnitTestExecutionResult(dist.testDir)
+        result.assertTestClassesExecuted('org.gradle.Test1')
+        result.testClass('org.gradle.Test1').assertTestPassed('testRenamesItself')
+    }
+
+    @Test
     public void reportsAndBreaksBuildWhenTestFails() {
         TestFile testDir = dist.getTestDir();
         TestFile buildFile = testDir.file('build.gradle');
@@ -66,6 +81,7 @@ public class JUnitIntegrationTest {
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenTest FAILED'));
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenBefore FAILED'));
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenAfter FAILED'));
+        assertThat(failure.getError(), containsLine('Test org.gradle.BrokenBeforeAndAfter FAILED'));
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenBeforeClass FAILED'));
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenAfterClass FAILED'));
         assertThat(failure.getError(), containsLine('Test org.gradle.BrokenConstructor FAILED'));
@@ -79,6 +95,7 @@ public class JUnitIntegrationTest {
                 'org.gradle.BrokenAfter',
                 'org.gradle.BrokenBeforeClass',
                 'org.gradle.BrokenAfterClass',
+                'org.gradle.BrokenBeforeAndAfter',
                 'org.gradle.BrokenConstructor',
                 'org.gradle.BrokenException',
                 'org.gradle.Unloadable')
@@ -88,6 +105,7 @@ public class JUnitIntegrationTest {
         result.testClass('org.gradle.BrokenAfterClass').assertTestFailed('classMethod', equalTo('java.lang.AssertionError: failed'))
         result.testClass('org.gradle.BrokenBefore').assertTestFailed('ok', equalTo('java.lang.AssertionError: failed'))
         result.testClass('org.gradle.BrokenAfter').assertTestFailed('ok', equalTo('java.lang.AssertionError: failed'))
+        result.testClass('org.gradle.BrokenBeforeAndAfter').assertTestFailed('ok', equalTo('java.lang.AssertionError: before failed'), equalTo('java.lang.AssertionError: after failed'))
         result.testClass('org.gradle.BrokenConstructor').assertTestFailed('ok', equalTo('java.lang.AssertionError: failed'))
         result.testClass('org.gradle.BrokenException').assertTestFailed('broken', startsWith('Could not determine failure message for exception of type org.gradle.BrokenException$BrokenRuntimeException: '))
         result.testClass('org.gradle.Unloadable').assertTestFailed('initializationError', equalTo('java.lang.AssertionError: failed'))
@@ -284,7 +302,7 @@ public class JUnitIntegrationTest {
                 void beforeSuite(TestDescriptor suite) { println "START [$suite] [$suite.name]" }
                 void afterSuite(TestDescriptor suite, TestResult result) { println "FINISH [$suite] [$suite.name] [$result.resultType] [$result.testCount]" }
                 void beforeTest(TestDescriptor test) { println "START [$test] [$test.name]" }
-                void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.resultType] [$result.testCount] [$result.error]" }
+                void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.resultType] [$result.testCount] [$result.exception]" }
             }
         '''
 
@@ -332,7 +350,7 @@ public class JUnitIntegrationTest {
                 void beforeSuite(TestDescriptor suite) { println "START [$suite] [$suite.name]" }
                 void afterSuite(TestDescriptor suite, TestResult result) { println "FINISH [$suite] [$suite.name]" }
                 void beforeTest(TestDescriptor test) { println "START [$test] [$test.name]" }
-                void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.error]" }
+                void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.exception]" }
             }
         '''
 
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitTestExecutionResult.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitTestExecutionResult.groovy
index 5228053..ed2f2e6 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitTestExecutionResult.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitTestExecutionResult.groovy
@@ -87,12 +87,16 @@ class JUnitTestClassExecutionResult implements TestClassExecutionResult {
         this
     }
 
-    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String> messageMatcher) {
+    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String>... messageMatchers) {
         Map<String, Node> testMethods = findTests()
         assertThat(testMethods.keySet(), hasItem(name))
-        assertThat(testMethods[name].failure.size(), equalTo(1))
-        def failure = testMethods[name].failure[0]
-        assertThat(failure. at message.text(), messageMatcher)
+
+        def failures = testMethods[name].failure
+        assertThat("Expected ${messageMatchers.length} failures. Found: $failures", failures.size(), equalTo(messageMatchers.length))
+
+        for (int i = 0; i < messageMatchers.length; i++) {
+            assertThat(failures[i]. at message.text(), messageMatchers[i])
+        }
         this
     }
 
@@ -131,7 +135,6 @@ class JUnitTestClassExecutionResult implements TestClassExecutionResult {
                 assertThat(node. at classname.text(), equalTo(testClassName))
                 assertThat(node. at name.text(), not(equalTo('')))
                 assertThat(node. at time.text(), not(equalTo('')))
-                assertThat(node.failure.size(), not(greaterThan(1)))
                 node.failure.each { failure ->
                     assertThat(failure. at message.size(), equalTo(1))
                     assertThat(failure. at type.text(), not(equalTo('')))
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserguideIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserguideIntegrationTest.groovy
deleted file mode 100644
index 70c23a1..0000000
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserguideIntegrationTest.groovy
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2010 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 org.gradle.integtests
-
-import org.gradle.integtests.fixtures.GradleDistribution
-import org.gradle.integtests.fixtures.GradleDistributionExecuter
-import org.gradle.util.TestFile
-import org.junit.Assert
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-/**
- * @author Hans Dockter
- */
- at RunWith (DistributionIntegrationTestRunner.class)
-class UserguideIntegrationTest {
-
-    private static Logger logger = LoggerFactory.getLogger(UserguideIntegrationTest)
-
-    @Rule public final GradleDistribution dist = new GradleDistribution()
-    @Rule public final GradleDistributionExecuter executer = new GradleDistributionExecuter()
-
-    @Test
-    public void apiLinks() {
-        TestFile gradleHome = dist.gradleHomeDir         
-        TestFile userguideInfoDir = dist.userGuideInfoDir
-        Node links = new XmlParser().parse(new File(userguideInfoDir, 'links.xml'))
-        links.children().each {Node link ->
-            String classname = link.'@className'
-            String lang = link.'@lang'
-            File classDocFile = new File(gradleHome, "docs/${lang}doc/${classname.replace('.', '/')}.html")
-            Assert.assertTrue("Could not find javadoc for class '$classname' referenced in userguide: $classDocFile does not exist.", classDocFile.isFile())
-        }
-    }
-}
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistribution.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistribution.java
index bd4425a..551ded7 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistribution.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistribution.java
@@ -43,7 +43,7 @@ public class GradleDistribution implements MethodRule, TestFileContext, BasicGra
         SAMPLES_DIR = file("integTest.samplesdir", new File(GRADLE_HOME_DIR, "samples").getAbsolutePath());
         USER_GUIDE_OUTPUT_DIR = file("integTest.userGuideOutputDir",
                 "subprojects/gradle-docs/src/samples/userguideOutput");
-        USER_GUIDE_INFO_DIR = file("integTest.userGuideInfoDir", "subprojects/gradle-docs/build/src/docbook");
+        USER_GUIDE_INFO_DIR = file("integTest.userGuideInfoDir", "subprojects/gradle-docs/build/src");
         DISTS_DIR = file("integTest.distsDir", "build/distributions");
     }
 
@@ -51,6 +51,11 @@ public class GradleDistribution implements MethodRule, TestFileContext, BasicGra
         this.userHome = USER_HOME_DIR;
     }
 
+    @Override
+    public String toString() {
+        return String.format("Gradle %s", new GradleVersion().getVersion());
+    }
+
     public boolean worksWith(Jvm jvm) {
         return jvm.isJava5Compatible();
     }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistributionExecuter.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistributionExecuter.java
index 1cd7e19..50321e4 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistributionExecuter.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleDistributionExecuter.java
@@ -123,7 +123,8 @@ public class GradleDistributionExecuter extends AbstractGradleExecuter implement
         GradleExecuter returnedExecuter = inProcessGradleExecuter;
 
         if (EXECUTER != Executer.embedded || !inProcessGradleExecuter.canExecute()) {
-            ForkingGradleExecuter forkingGradleExecuter = EXECUTER == Executer.daemon ? new DaemonGradleExecuter(dist.getGradleHomeDir()) : new ForkingGradleExecuter(dist.getGradleHomeDir());
+            boolean useDaemon = EXECUTER == Executer.daemon && getExecutable() == null;
+            ForkingGradleExecuter forkingGradleExecuter = useDaemon ? new DaemonGradleExecuter(dist.getGradleHomeDir()) : new ForkingGradleExecuter(dist.getGradleHomeDir());
             copyTo(forkingGradleExecuter);
             returnedExecuter = forkingGradleExecuter;
         }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/TestClassExecutionResult.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/TestClassExecutionResult.java
index d916261..46d9964 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/TestClassExecutionResult.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/TestClassExecutionResult.java
@@ -32,7 +32,7 @@ public interface TestClassExecutionResult {
     /**
      * Asserts that the given test failed.
      */
-    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String> messageMatcher);
+    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String>... messageMatchers);
 
     /**
      * Asserts that the given config method passed.
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/testng/TestNGExecutionResult.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/testng/TestNGExecutionResult.groovy
index efc08c5..9a6f441 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/testng/TestNGExecutionResult.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/testng/TestNGExecutionResult.groovy
@@ -89,10 +89,16 @@ private class TestNgTestClassExecutionResult implements TestClassExecutionResult
         this
     }
 
-    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String> messageMatcher) {
+    TestClassExecutionResult assertTestFailed(String name, Matcher<? super String>... messageMatchers) {
         def testMethodNode = findTestMethod(name)
         assertEquals('FAIL', testMethodNode. at status as String)
-        assertThat(testMethodNode.exception[0].message[0].text().trim(), messageMatcher)
+
+        def exceptions = testMethodNode.exception
+        assertThat(exceptions.size(), equalTo(messageMatchers.length))
+
+        for (int i = 0; i < messageMatchers.length; i++) {
+            assertThat(exceptions[i].message[0].text().trim(), messageMatchers[i])
+        }
         this
     }
 
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest/shared/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest/shared/build.gradle
index 667d839..eb60aff 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest/shared/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest/shared/build.gradle
@@ -1,6 +1,6 @@
 
 task wrapper(type: Wrapper) {
-    doFirst {
+    if (project.hasProperty('distVersion')) {
         gradleVersion = distVersion
         urlRoot = new File(project.distZip).parentFile.toURI().toString()
     }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/build.gradle
new file mode 100644
index 0000000..ca04df1
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/build.gradle
@@ -0,0 +1,9 @@
+apply plugin: 'java'
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testCompile "junit:junit:${junitVersion}"
+}
\ No newline at end of file
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/src/test/java/org/gradle/Test1.java b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/src/test/java/org/gradle/Test1.java
new file mode 100644
index 0000000..5673512
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/canRunJunit3Tests/src/test/java/org/gradle/Test1.java
@@ -0,0 +1,9 @@
+package org.gradle;
+
+import junit.framework.TestCase;
+
+public class Test1 extends TestCase {
+    public void testRenamesItself() {
+        setName("a test that renames itself");
+    }
+}
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/reportsAndBreaksBuildWhenTestFails/src/test/java/org/gradle/BrokenBeforeAndAfter.java b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/reportsAndBreaksBuildWhenTestFails/src/test/java/org/gradle/BrokenBeforeAndAfter.java
new file mode 100644
index 0000000..c8931c1
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/reportsAndBreaksBuildWhenTestFails/src/test/java/org/gradle/BrokenBeforeAndAfter.java
@@ -0,0 +1,23 @@
+package org.gradle;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class BrokenBeforeAndAfter {
+    @Before
+    public void brokenBefore() {
+        fail("before failed");
+    }
+
+    @After
+    public void brokenAfter() {
+        fail("after failed");
+    }
+
+    @Test
+    public void ok() {
+    }
+}
\ No newline at end of file
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/canListenForTestResults/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/canListenForTestResults/build.gradle
index 0a58919..e0d7f49 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/canListenForTestResults/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/canListenForTestResults/build.gradle
@@ -16,5 +16,5 @@ class TestListenerImpl implements TestListener {
 
     void beforeTest(TestDescriptor test) { println "START [$test] [$test.name]" }
 
-    void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.error]" }
+    void afterTest(TestDescriptor test, TestResult result) { println "FINISH [$test] [$test.name] [$result.exception]" }
 }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Failing/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Failing/build.gradle
index d72a901..ee4443f 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Failing/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Failing/build.gradle
@@ -7,7 +7,7 @@ repositories {
 }
 
 dependencies {
-	groovy "org.codehaus.groovy:groovy-all:1.7.5"
+	groovy "org.codehaus.groovy:groovy-all:1.7.6"
 
     testCompile 'org.testng:testng:5.13.1'
 }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Passing/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Passing/build.gradle
index d72a901..ee4443f 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Passing/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/testng/TestNGIntegrationTest/groovyJdk15Passing/build.gradle
@@ -7,7 +7,7 @@ repositories {
 }
 
 dependencies {
-	groovy "org.codehaus.groovy:groovy-all:1.7.5"
+	groovy "org.codehaus.groovy:groovy-all:1.7.6"
 
     testCompile 'org.testng:testng:5.13.1'
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Project.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Project.java
index f17e00b..47b6df9 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Project.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Project.java
@@ -72,25 +72,25 @@ import java.util.Set;
  * <p>A project is essentially a collection of {@link Task} objects. Each task performs some basic piece of work, such
  * as compiling classes, or running unit tests, or zipping up a WAR file. You add tasks to a project using one of the
  * {@code add()} methods on {@link TaskContainer}, such as {@link TaskContainer#add(String)}.  You can locate existing
- * tasks using one of the lookup methods on {@link TaskContainer}, such as {@link TaskContainer#getByName(String)}.</p>
+ * tasks using one of the lookup methods on {@link TaskContainer}, such as {@link org.gradle.api.tasks.TaskCollection#getByName(String)}.</p>
  *
  * <h3>Dependencies</h3>
  *
  * <p>A project generally has a number of dependencies it needs in order to do its work.  Also, a project generally
  * produces a number of artifacts, which other projects can use. Those dependencies are grouped in configurations, and
  * can be retrieved and uploaded from repositories. You use the {@link org.gradle.api.artifacts.ConfigurationContainer}
- * returned by {@link #getConfigurations()} ()} method to manage the configurations. The {@link
+ * returned by {@link #getConfigurations()} method to manage the configurations. The {@link
  * org.gradle.api.artifacts.dsl.DependencyHandler} returned by {@link #getDependencies()} method to manage the
- * dependencies. The {@link org.gradle.api.artifacts.dsl.ArtifactHandler} returned by {@link #getArtifacts()} ()} method
- * to manage the artifacts. The {@link org.gradle.api.artifacts.dsl.RepositoryHandler} returned by {@link
- * #getRepositories()} ()} method to manage the repositories.</p>
+ * dependencies. The {@link org.gradle.api.artifacts.dsl.ArtifactHandler} returned by {@link #getArtifacts()} method to
+ * manage the artifacts. The {@link org.gradle.api.artifacts.dsl.RepositoryHandler} returned by {@link
+ * #getRepositories()} method to manage the repositories.</p>
  *
  * <h3>Multi-project Builds</h3>
  *
  * <p>Projects are arranged into a hierarchy of projects. A project has a name, and a fully qualified path which
  * uniquely identifies it in the hierarchy.</p>
  *
- * <h3>Using a Project in a Build File</h3>
+ * <h3>Build scripts</h3>
  *
  * <p>Gradle executes the project's build file against the <code>Project</code> instance to configure the project. Any
  * property or method which your script uses which is not defined in the script is delegated through to the associated
@@ -191,8 +191,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the root project for the hierarchy that this project belongs to.  In the case of a single-project
-     * build, this method returns this project.</p> <p/> <p>You can access this property in your build file using
-     * <code>rootProject</code></p>
+     * build, this method returns this project.</p>
      *
      * @return The root project. Never returns null.
      */
@@ -200,7 +199,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the root directory of this project. The root directory is the project directory of the root
-     * project.</p> <p/> <p>You can access this property in your build file using <code>rootDir</code></p>
+     * project.</p>
      *
      * @return The root directory. Never returns null.
      */
@@ -208,8 +207,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the build directory of this project.  The build directory is the directory which all artifacts are
-     * generated into.  The default value for the build directory is <code><i>projectDir</i>/build</code></p> <p/>
-     * <p>You can access this property in your build file using <code>buildDir</code></p>
+     * generated into.  The default value for the build directory is <code><i>projectDir</i>/build</code></p>
      *
      * @return The build directory. Never returns null.
      */
@@ -218,7 +216,7 @@ public interface Project extends Comparable<Project> {
     /**
      * <p>Sets the build directory of this project. The build directory is the directory which all artifacts are
      * generated into. The path parameter is evaluated as described for {@link #file(Object)}. This mean you can use,
-     * amongst other things, a relative or absolute path or File object to specify the build directory. </p>
+     * amongst other things, a relative or absolute path or File object to specify the build directory.</p>
      *
      * @param path The build directory. This is evaluated as for {@link #file(Object)}
      */
@@ -226,8 +224,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the name of the build directory of this project. It is resolved relative to the project directory of
-     * this project to determine the build directory. The default value is {@value #DEFAULT_BUILD_DIR_NAME}.</p> <p/>
-     * <p>You can access this property in your build file using <code>buildDirName</code></p>
+     * this project to determine the build directory. The default value is {@value #DEFAULT_BUILD_DIR_NAME}.</p>
      *
      * @return The build dir name. Never returns null.
      */
@@ -245,16 +242,14 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the build file Gradle will evaluate against this project object. The default is <code> {@value
-     * #DEFAULT_BUILD_FILE}</code>. If an embedded script is provided the build file will be null. <p/> <p>You can
-     * access this property in your build file using <code>buildFile</code></p>
+     * #DEFAULT_BUILD_FILE}</code>. If an embedded script is provided the build file will be null. </p>
      *
      * @return Current build file. May return null.
      */
     File getBuildFile();
 
     /**
-     * <p>Returns the parent project of this project, if any.</p> <p/> <p>You can access this property in your build
-     * file using <code>parent</code></p>
+     * <p>Returns the parent project of this project, if any.</p>
      *
      * @return The parent project, or null if this is the root project.
      */
@@ -262,8 +257,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the name of this project. The project's name is not necessarily unique within a project hierarchy. You
-     * should use the {@link #getPath()} method for a unique identifier for the project.</p> <p/> <p>You can access this
-     * property in your build file using <code>name</code></p>
+     * should use the {@link #getPath()} method for a unique identifier for the project.</p>
      *
      * @return The name of this project. Never return null.
      */
@@ -284,36 +278,55 @@ public interface Project extends Comparable<Project> {
     void setDescription(String description);
 
     /**
-     * <p>Returns the group of this project. Gradle always uses the toString() value of a group. The group defaults to
-     * the path with dots a separators.</p> <p/> <p>You can access this property in your build file using
-     * <code>group</code></p>
+     * <p>Returns the group of this project. Gradle always uses the {@code toString()} value of the group. The group
+     * defaults to the path with dots a separators.</p>
      *
      * @return The group of this project. Never returns null.
      */
     Object getGroup();
 
     /**
-     * <p>Returns the version of this project. Gradle always uses the toString() value of a version. The version
-     * defaults to {@value #DEFAULT_VERSION}.</p> <p/> <p>You can access this property in your build file using
-     * <code>version</code></p>
+     * <p>Sets the group of this project.</p>
+     *
+     * @param group The group of this project. Must not be null.
+     */
+    void setGroup(Object group);
+
+    /**
+     * <p>Returns the version of this project. Gradle always uses the {@code toString()} value of the version. The
+     * version defaults to {@value #DEFAULT_VERSION}.</p>
      *
      * @return The version of this project. Never returns null.
      */
     Object getVersion();
 
     /**
-     * <p>Returns the status of this project. Gradle always uses the toString() value of a version. The status defaults
-     * to {@value #DEFAULT_STATUS}.</p> <p/> <p>You can access this property in your build file using
-     * <code>status</code></p> <p/> The status of the project is only relevant, if you upload libraries together with a
-     * module descriptor. The status specified here, will be part of this module descriptor.
+     * <p>Sets the version of this project.</p>
+     *
+     * @param version The version of this project. Must not be null.
+     */
+    void setVersion(Object version);
+
+    /**
+     * <p>Returns the status of this project. Gradle always uses the {@code toString()} value of the status. The status
+     * defaults to {@value #DEFAULT_STATUS}.</p>
+     *
+     * <p>The status of the project is only relevant, if you upload libraries together with a module descriptor. The
+     * status specified here, will be part of this module descriptor.</p>
      *
      * @return The status of this project. Never returns null.
      */
     Object getStatus();
 
     /**
-     * <p>Returns the direct children of this project.</p> <p/> <p>You can access this property in your build file using
-     * <code>childProjects</code></p>
+     * Sets the status of this project.
+     *
+     * @param status The status. Must not be null.
+     */
+    void setStatus(Object status);
+
+    /**
+     * <p>Returns the direct children of this project.</p>
      *
      * @return A map from child project name to child project. Returns an empty map if this this project does not have
      *         any children.
@@ -321,8 +334,7 @@ public interface Project extends Comparable<Project> {
     Map<String, Project> getChildProjects();
 
     /**
-     * <p>Returns the set of projects which this project depends on.</p> <p/> <p>You can access this property in your
-     * build file using <code>dependsOnProjects</code></p>
+     * <p>Returns the set of projects which this project depends on.</p>
      *
      * @return The set of projects. Returns an empty set if this project depends on no projects.
      */
@@ -330,11 +342,21 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Sets a property of this project.  This method searches for a property with the given name in the following
-     * locations, and sets the property on the first location where it finds the property.</p> <p/> <ol> <p/> <li>The
-     * project object itself.  For example, the <code>rootDir</code> project property.</li> <p/> <li>The project's
-     * {@link Convention} object.  For example, the <code>srcRootName</code> java plugin property.</li> <p/> <li>The
-     * project's additional properties.</li> <p/> </ol> <p/> <p>If the property is not found in any of these locations,
-     * it is added to the project's additional properties.</p>
+     * locations, and sets the property on the first location where it finds the property.</p>
+     *
+     * <ol>
+     *
+     * <li>The project object itself.  For example, the <code>rootDir</code> project property.</li>
+     *
+     * <li>The project's {@link Convention} object.  For example, the <code>srcRootName</code> java plugin
+     * property.</li>
+     *
+     * <li>The project's additional properties.</li>
+     *
+     * </ol>
+     *
+     * <p>If the property is not found in any of these locations, it is added to the project's additional
+     * properties.</p>
      *
      * @param name The name of the property
      * @param value The value of the property
@@ -347,23 +369,19 @@ public interface Project extends Comparable<Project> {
      * <code>name</code>. This method also allows you to access project properties from a scope where the property may
      * be hidden, such as, for example, from a method or closure. </p>
      *
-     * <p>You can access this property in your build file using <code>project</code></p>
-     *
      * @return This project. Never returns null.
      */
     Project getProject();
 
     /**
-     * <p>Returns the set containing this project and its subprojects.</p> <p/> <p>You can access this property in your
-     * build file using <code>allprojects</code></p>
+     * <p>Returns the set containing this project and its subprojects.</p>
      *
      * @return The set of projects.
      */
     Set<Project> getAllprojects();
 
     /**
-     * <p>Returns the set containing the subprojects of this project.</p> <p/> <p>You can access this property in your
-     * build file using <code>subprojects</code></p>
+     * <p>Returns the set containing the subprojects of this project.</p>
      *
      * @return The set of projects.  Returns an empty set if this project has no subprojects.
      */
@@ -393,10 +411,12 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. Calling this method is equivalent to
-     * calling {@link #task(java.util.Map, String)} with an empty options map.</p> <p/> <p>After the task is added to
-     * the project, it is made available as a property of the project, so that you can reference the task by name in
-     * your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with the given name
-     * already exists in this project, an exception is thrown.</p>
+     * calling {@link #task(java.util.Map, String)} with an empty options map.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project, an exception is thrown.</p>
      *
      * @param name The name of the task to be created
      * @return The newly created task object
@@ -406,18 +426,32 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. A map of creation options can be
-     * passed to this method to control how the task is created. The following options are available:</p> <p/> <table>
-     * <p/> <tr><th>Option</th><th>Description</th><th>Default Value</th></tr> <p/> <tr><td><code>{@value
-     * org.gradle.api.Task#TASK_TYPE}</code></td><td>The class of the task to create.</td><td>{@link
-     * org.gradle.api.DefaultTask}</td></tr> <p/> <tr><td><code>{@value org.gradle.api.Task#TASK_OVERWRITE}</code></td><td>Replace
-     * an existing task?</td><td><code>false</code></td></tr> <p/> <tr><td><code>{@value
-     * org.gradle.api.Task#TASK_DEPENDS_ON}</code></td><td>A task name or set of task names which this task depends
-     * on</td><td><code>[]</code></td></tr> <p/> <tr><td><code>{@value org.gradle.api.Task#TASK_ACTION}</code></td><td>A
-     * closure or {@link Action} to add to the task.</td><td><code>null</code></td></tr> <p/> </table> <p/> <p>After the
-     * task is added to the project, it is made available as a property of the project, so that you can reference the
-     * task by name in your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with
-     * the given name already exists in this project and the <code>override</code> option is not set to true, an
-     * exception is thrown.</p>
+     * passed to this method to control how the task is created. The following options are available:</p>
+     *
+     * <table>
+     *
+     * <tr><th>Option</th><th>Description</th><th>Default Value</th></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_TYPE}</code></td><td>The class of the task to
+     * create.</td><td>{@link org.gradle.api.DefaultTask}</td></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_OVERWRITE}</code></td><td>Replace an existing
+     * task?</td><td><code>false</code></td></tr>
+     *
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_DEPENDS_ON}</code></td><td>A task name or set of task names which
+     * this task depends on</td><td><code>[]</code></td></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_ACTION}</code></td><td>A closure or {@link Action} to add to the
+     * task.</td><td><code>null</code></td></tr>
+     *
+     * </table>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project and the <code>override</code> option is not set
+     * to true, an exception is thrown.</p>
      *
      * @param args The task creation options.
      * @param name The name of the task to be created
@@ -429,11 +463,13 @@ public interface Project extends Comparable<Project> {
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. Before the task is returned, the given
      * closure is executed to configure the task. A map of creation options can be passed to this method to control how
-     * the task is created. See {@link #task(java.util.Map, String)} for the available options.</p> <p/> <p>After the
-     * task is added to the project, it is made available as a property of the project, so that you can reference the
-     * task by name in your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with
-     * the given name already exists in this project and the <code>override</code> option is not set to true, an
-     * exception is thrown.</p>
+     * the task is created. See {@link #task(java.util.Map, String)} for the available options.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project and the <code>override</code> option is not set
+     * to true, an exception is thrown.</p>
      *
      * @param args The task creation options.
      * @param name The name of the task to be created
@@ -458,10 +494,12 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. Calling this method is equivalent to
-     * calling {@link #createTask(java.util.Map, String)} with an empty options map.</p> <p/> <p>After the task is added
-     * to the project, it is made available as a property of the project, so that you can reference the task by name in
-     * your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with the given name
-     * already exists in this project, an exception is thrown.</p>
+     * calling {@link #createTask(java.util.Map, String)} with an empty options map.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project, an exception is thrown.</p>
      *
      * @param name The name of the task to be created
      * @return The newly created task object
@@ -474,10 +512,12 @@ public interface Project extends Comparable<Project> {
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. Before the task is returned, the given
      * action is passed to the task's {@link Task#doFirst(Action)} method. Calling this method is equivalent to calling
-     * {@link #createTask(java.util.Map, String, Action)} with an empty options map.</p> <p/> <p>After the task is added
-     * to the project, it is made available as a property of the project, so that you can reference the task by name in
-     * your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with the given name
-     * already exists in this project, an exception is thrown.</p>
+     * {@link #createTask(java.util.Map, String, Action)} with an empty options map.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project, an exception is thrown.</p>
      *
      * @param name The name of the task to be created
      * @param action The action to be passed to the {@link Task#doFirst(Action)} method of the created task.
@@ -490,16 +530,28 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. A map of creation options can be
-     * passed to this method to control how the task is created. The following options are available:</p> <p/> <table>
-     * <p/> <tr><th>Option</th><th>Description</th><th>Default Value</th></tr> <p/> <tr><td><code>{@value
-     * org.gradle.api.Task#TASK_TYPE}</code></td><td>The class of the task to create.</td><td>{@link
-     * org.gradle.api.DefaultTask}</td></tr> <p/> <tr><td><code>{@value org.gradle.api.Task#TASK_OVERWRITE}</code></td><td>Replace
-     * an existing task?</td><td><code>false</code></td></tr> <p/> <tr><td><code>{@value
-     * org.gradle.api.Task#TASK_DEPENDS_ON}</code></td><td>A task name or set of task names which this task depends
-     * on</td><td><code>[]</code></td></tr> <p/> </table> <p/> <p>After the task is added to the project, it is made
-     * available as a property of the project, so that you can reference the task by name in your build file.  See <a
-     * href="#properties">here</a> for more details</p> <p/> <p>If a task with the given name already exists in this
-     * project and the <code>override</code> option is not set to true, an exception is thrown.</p>
+     * passed to this method to control how the task is created. The following options are available:</p>
+     *
+     * <table>
+     *
+     * <tr><th>Option</th><th>Description</th><th>Default Value</th></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_TYPE}</code></td><td>The class of the task to
+     * create.</td><td>{@link org.gradle.api.DefaultTask}</td></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_OVERWRITE}</code></td><td>Replace an existing
+     * task?</td><td><code>false</code></td></tr>
+     *
+     * <tr><td><code>{@value org.gradle.api.Task#TASK_DEPENDS_ON}</code></td><td>A task name or set of task names which
+     * this task depends on</td><td><code>[]</code></td></tr>
+     *
+     * </table>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project and the <code>override</code> option is not set
+     * to true, an exception is thrown.</p>
      *
      * @param args The task creation options.
      * @param name The name of the task to be created
@@ -514,10 +566,13 @@ public interface Project extends Comparable<Project> {
      * <p>Creates a {@link Task} with the given name and adds it to this project. Before the task is returned, the given
      * action is passed to the task's {@link Task#doFirst(Action)} method. A map of creation options can be passed to
      * this method to control how the task is created. See {@link #createTask(java.util.Map, String)} for the available
-     * options.</p> <p/> <p>After the task is added to the project, it is made available as a property of the project,
-     * so that you can reference the task by name in your build file.  See <a href="#properties">here</a> for more
-     * details</p> <p/> <p>If a task with the given name already exists in this project and the <code>override</code>
-     * option is not set to true, an exception is thrown.</p>
+     * options.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project and the <code>override</code> option is not set
+     * to true, an exception is thrown.</p>
      *
      * @param args The task creation options.
      * @param name The name of the task to be created
@@ -532,10 +587,12 @@ public interface Project extends Comparable<Project> {
     /**
      * <p>Creates a {@link Task} with the given name and adds it to this project. Before the task is returned, the given
      * action closure is passed to the task's {@link Task#doFirst(Closure)} method. Calling this method is equivalent to
-     * calling {@link #createTask(java.util.Map, String, Closure)} with an empty options map.</p> <p/> <p>After the task
-     * is added to the project, it is made available as a property of the project, so that you can reference the task by
-     * name in your build file.  See <a href="#properties">here</a> for more details</p> <p/> <p>If a task with the
-     * given name already exists in this project, an exception is thrown.</p>
+     * calling {@link #createTask(java.util.Map, String, Closure)} with an empty options map.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project, an exception is thrown.</p>
      *
      * @param name The name of the task to be created
      * @param action The closure to be passed to the {@link Task#doFirst(Closure)} method of the created task.
@@ -550,10 +607,13 @@ public interface Project extends Comparable<Project> {
      * <p>Creates a {@link Task} with the given name and adds it to this project. Before the task is returned, the given
      * action closure is passed to the task's {@link Task#doFirst(Closure)} method. A map of creation options can be
      * passed to this method to control how the task is created. See {@link #createTask(java.util.Map, String)} for the
-     * available options.</p> <p/> <p>After the task is added to the project, it is made available as a property of the
-     * project, so that you can reference the task by name in your build file.  See <a href="#properties">here</a> for
-     * more details</p> <p/> <p>If a task with the given name already exists in this project and the
-     * <code>override</code> option is not set to true, an exception is thrown.</p>
+     * available options.</p>
+     *
+     * <p>After the task is added to the project, it is made available as a property of the project, so that you can
+     * reference the task by name in your build file.  See <a href="#properties">here</a> for more details</p>
+     *
+     * <p>If a task with the given name already exists in this project and the <code>override</code> option is not set
+     * to true, an exception is thrown.</p>
      *
      * @param args The task creation options.
      * @param name The name of the task to be created
@@ -692,8 +752,7 @@ public interface Project extends Comparable<Project> {
     Set<Task> getTasksByName(String name, boolean recursive);
 
     /**
-     * <p>The directory containing the project build file.</p> <p/> <p>You can access this property in your build file
-     * using <code>projectDir</code></p>
+     * <p>The directory containing the project build file.</p>
      *
      * @return The project directory. Never returns null.
      */
@@ -953,7 +1012,7 @@ public interface Project extends Comparable<Project> {
 
     /**
      * <p>Returns the <code>AntBuilder</code> for this project. You can use this in your build file to execute ant
-     * tasks.</p> <p/> <p>You can access this property in your build file using <code>ant</code></p>
+     * tasks.</p>
      *
      * @return The <code>AntBuilder</code> for this project. Never returns null.
      */
@@ -971,8 +1030,7 @@ public interface Project extends Comparable<Project> {
     /**
      * <p>Executes the given closure against the <code>AntBuilder</code> for this project. You can use this in your
      * build file to execute ant tasks. The <code>AntBuild</code> is passed to the closure as the closure's
-     * delegate.</p> <p/> <p>You can call this method in your build file using <code>ant</code> followed by a code
-     * block.</p>
+     * delegate.</p>
      *
      * @param configureClosure The closure to execute against the <code>AntBuilder</code>.
      * @return The <code>AntBuilder</code>. Never returns null.
@@ -987,9 +1045,10 @@ public interface Project extends Comparable<Project> {
     ConfigurationContainer getConfigurations();
 
     /**
-     * Configures the dependency configurations for this project. Executes the given closure against the {@link
-     * org.gradle.api.artifacts.ConfigurationContainer} for this project. The {@link
-     * org.gradle.api.artifacts.ConfigurationContainer} is passed to the closure as the closure's delegate.
+     * <p>Configures the dependency configurations for this project.
+     *
+     * <p>This method executes the given closure against the {@link ConfigurationContainer} for this project. The {@link
+     * ConfigurationContainer} is passed to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the dependency configurations.
      */
@@ -1001,16 +1060,17 @@ public interface Project extends Comparable<Project> {
     ArtifactHandler getArtifacts();
 
     /**
-     * Configures the published artifacts for this project. Executes the given closure against the {@link
-     * ArtifactHandler} for this project. The {@link ArtifactHandler} is passed to the closure as the closure's
-     * delegate.
+     * <p>Configures the published artifacts for this project.
+     *
+     * <p>This method executes the given closure against the {@link ArtifactHandler} for this project. The {@link
+     * ArtifactHandler} is passed to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the published artifacts.
      */
     void artifacts(Closure configureClosure);
 
     /**
-     * <p>Return the {@link Convention} for this project.</p> <p/> <p>You can access this property in your build file
+     * <p>Returns the {@link Convention} for this project.</p> <p/> <p>You can access this property in your build file
      * using <code>convention</code>. You can also can also access the properties and methods of the convention object
      * as if they were properties and methods of this project. See <a href="#properties">here</a> for more details</p>
      *
@@ -1042,34 +1102,40 @@ public interface Project extends Comparable<Project> {
     TaskContainer getTasks();
 
     /**
-     * <p>Executes the given {@link Action} against the subprojects of this project.</p>
+     * <p>Configures the sub-projects of this project</p>
+     *
+     * <p>This method executes the given {@link Action} against the sub-projects of this project.</p>
      *
      * @param action The action to execute.
      */
     void subprojects(Action<? super Project> action);
 
     /**
-     * <p>Executes the given closure against each of the sub-projects of this project. The target project is passed to
-     * the closure as the closure's delegate. </p> <p/> <p>You can call this method in your build file using
-     * <code>subprojects</code> followed by a code block.</p>
+     * <p>Configures the sub-projects of this project.</p>
      *
-     * @param configureClosure The closure to execute. The closure receives no parameters.
+     * <p>This method executes the given closure against each of the sub-projects of this project. The target {@link
+     * Project} is passed to the closure as the closure's delegate.</p>
+     *
+     * @param configureClosure The closure to execute.
      */
     void subprojects(Closure configureClosure);
 
     /**
-     * <p>Executes the given {@link Action} against this project and its subprojects.</p>
+     * <p>Configures this project and each of its sub-projects.</p>
+     *
+     * <p>This method executes the given {@link Action} against this project and each of its sub-projects.</p>
      *
      * @param action The action to execute.
      */
     void allprojects(Action<? super Project> action);
 
     /**
-     * <p>Executes the given closure against this project and its sub-projects. The target project is passed to the
-     * closure as the closure's delegate.</p> <p/> <p>You can call this method in your build file using
-     * <code>allprojects</code> followed by a code block.</p>
+     * <p>Configures this project and each of its sub-projects.</p>
      *
-     * @param configureClosure The closure to execute. The closure receives no parameters.
+     * <p>This method executes the given closure against this project and its sub-projects. The target {@link Project}
+     * is passed to the closure as the closure's delegate.</p>
+     *
+     * @param configureClosure The closure to execute.
      */
     void allprojects(Closure configureClosure);
 
@@ -1151,16 +1217,14 @@ public interface Project extends Comparable<Project> {
     Object property(String propertyName) throws MissingPropertyException;
 
     /**
-     * <p>Returns the logger for this project. You can use this in your build file to write log messages.</p> <p/>
-     * <p>You can use this property in your build file using <code>logger</code>.</p>
+     * <p>Returns the logger for this project. You can use this in your build file to write log messages.</p>
      *
      * @return The logger. Never returns null.
      */
     Logger getLogger();
 
     /**
-     * <p>Returns the {@link org.gradle.api.invocation.Gradle} which this project belongs to.</p> <p/> <p>You can use
-     * this property in your build file using <code>gradle</code>.</p>
+     * <p>Returns the {@link org.gradle.api.invocation.Gradle} invocation which this project belongs to.</p>
      *
      * @return The Gradle object. Never returns null.
      */
@@ -1255,8 +1319,10 @@ public interface Project extends Comparable<Project> {
     RepositoryHandler getRepositories();
 
     /**
-     * Configures the repositories for this project. Executes the given closure against the {@link RepositoryHandler}
-     * for this project. The {@link RepositoryHandler} is passed to the closure as the closure's delegate.
+     * <p>Configures the repositories for this project.
+     *
+     * <p>This method executes the given closure against the {@link RepositoryHandler} for this project. The {@link
+     * RepositoryHandler} is passed to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the repositories.
      */
@@ -1280,8 +1346,10 @@ public interface Project extends Comparable<Project> {
     DependencyHandler getDependencies();
 
     /**
-     * Configures the dependencies for this project. Executes the given closure against the {@link DependencyHandler}
-     * for this project. The {@link DependencyHandler} is passed to the closure as the closure's delegate.
+     * <p>Configures the dependencies for this project.
+     *
+     * <p>This method executes the given closure against the {@link DependencyHandler} for this project. The {@link
+     * DependencyHandler} is passed to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the dependencies.
      */
@@ -1304,16 +1372,18 @@ public interface Project extends Comparable<Project> {
     ScriptHandler getBuildscript();
 
     /**
-     * Configures the build script classpath for this project. The given closure is executed against this project's
-     * {@link ScriptHandler}. The {@link ScriptHandler} is passed to the closure as the closure's delegate.
+     * <p>Configures the build script classpath for this project.
+     *
+     * <p>The given closure is executed against this project's {@link ScriptHandler}. The {@link ScriptHandler} is
+     * passed to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the build script classpath.
      */
     void buildscript(Closure configureClosure);
 
     /**
-     * Copy the specified files.  The given closure is used to configure a {@link CopySpec}, which is then used to copy
-     * the files. Example:
+     * Copies the specified files.  The given closure is used to configure a {@link CopySpec}, which is then used to
+     * copy the files. Example:
      * <pre>
      * copy {
      *    from configurations.runtime
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Script.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Script.java
index ec94053..9243a89 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Script.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Script.java
@@ -32,9 +32,9 @@ import java.net.URI;
 import java.util.Map;
 
 /**
- * <p>The base class for all scripts executed by Gradle. This is a extension to the Groovy {@code Script} class, which
- * adds in some Gradle-specific methods. As your compiled script class will implement this interface, you can use the
- * methods and properties declared here directly in your script.</p>
+ * <p>This interface is implemented by all Gradle scripts to add in some Gradle-specific methods. As your compiled
+ * script class will implement this interface, you can use the methods and properties declared by this interface
+ * directly in your script.</p>
  *
  * <p>Generally, a {@code Script} object will have a delegate object attached to it. For example, a build script will
  * have a {@link Project} instance attached to it, and an initialization script will have a {@link
@@ -43,17 +43,19 @@ import java.util.Map;
  */
 public interface Script {
     /**
-     * <p>Configures the delegate object for this script using plugins or scripts. The given closure is used to
-     * configure an {@link org.gradle.api.plugins.ObjectConfigurationAction} which is then used to configure the
-     * delegate object.</p>
+     * <p>Configures the delegate object for this script using plugins or scripts.
+     *
+     * <p>The given closure is used to configure an {@link org.gradle.api.plugins.ObjectConfigurationAction} which is
+     * then used to configure the delegate object.</p>
      *
      * @param closure The closure to configure the {@code ObjectConfigurationAction}.
      */
     void apply(Closure closure);
 
     /**
-     * <p>Configures the delegate object for this script using plugins or scripts. The following options are
-     * available:</p>
+     * <p>Configures the delegate object for this script using plugins or scripts.
+     *
+     * <p>The following options are available:</p>
      *
      * <ul><li>{@code from}: A script to apply to the delegate object. Accepts any path supported by {@link
      * #uri(Object)}.</li>
@@ -76,8 +78,10 @@ public interface Script {
     ScriptHandler getBuildscript();
 
     /**
-     * Configures the classpath for this script. The given closure is executed against this script's {@link
-     * ScriptHandler}. The {@link ScriptHandler} is passed to the closure as the closure's delegate.
+     * Configures the classpath for this script.
+     *
+     * <p>The given closure is executed against this script's {@link ScriptHandler}. The {@link ScriptHandler} is passed
+     * to the closure as the closure's delegate.
      *
      * @param configureClosure the closure to use to configure the script classpath.
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Task.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Task.java
index 0a083bd..0cadca3 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/Task.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/Task.java
@@ -61,7 +61,7 @@ import java.util.Set;
  *
  * <p>Groovy closures can also be used to provide a task action. When the action is executed, the closure is called with
  * the task as parameter.  You can add action closures to a task by calling {@link #doFirst(groovy.lang.Closure)} or
- * {@link #doLast(groovy.lang.Closure)}  or using the left-shift << operator.</p>
+ * {@link #doLast(groovy.lang.Closure)}  or using the left-shift {@code <<} operator.</p>
  *
  * <p>There are 2 special exceptions which a task action can throw to abort execution and continue without failing the
  * build. A task action can abort execution of the action and continue to the next action of the task by throwing a
@@ -90,8 +90,8 @@ import java.util.Set;
  *
  * <li>A {@link Buildable} object.</li>
  *
- * <li>A {@code Collection}, {@code Map} or an array. May contain any of the types listed here. The elements of the
- * collection/map/array are recursively converted to tasks.</li>
+ * <li>A {@code Iterable}, {@code Collection}, {@code Map} or array. May contain any of the types listed here. The elements of the
+ * iterable/collection/map/array are recursively converted to tasks.</li>
  *
  * <li>A {@code Callable}. The {@code call()} method may return any of the types listed here. Its return value is
  * recursively converted to tasks. A {@code null} return value is treated as an empty collection.</li>
@@ -222,7 +222,7 @@ public interface Task extends Comparable<Task> {
      * <p>You may add multiple such predicates. The task is skipped if any of the predicates return false.</p>
      *
      * <p>Typical usage (from Java):</p>
-     * <pre>myTask.onlyIf(new Spec<Task>() {
+     * <pre>myTask.onlyIf(new Spec<Task>() {
      *    boolean isSatisfiedBy(Task task) {
      *       return task.dependsOnTaskDidWork();
      *    }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/Configuration.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/Configuration.java
index c89237f..228b5cd 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/Configuration.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/Configuration.java
@@ -364,7 +364,7 @@ public interface Configuration extends FileCollection {
 
     /**
      * Creates a copy of this configuration that contains the dependencies directly in this configuration
-     * and those derived from superconfigurations.  The new configuation will be in the
+     * and those derived from superconfigurations.  The new configuration will be in the
      * UNRESOLVED state, but will retain all other attributes of this configuration except superconfigurations.
      * {@link #getHierarchy()} for the copy will not include any superconfigurations.
      * @return copy of this configuration
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/maven/Conf2ScopeMappingContainer.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/maven/Conf2ScopeMappingContainer.java
index 81961ee..5171b9a 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/maven/Conf2ScopeMappingContainer.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/maven/Conf2ScopeMappingContainer.java
@@ -21,7 +21,7 @@ import java.util.Collection;
 import java.util.Map;
 
 /**
- * Defines a set of rules for how to map the Gradle dependendencies to a pom. This mapping is based
+ * Defines a set of rules for how to map the Gradle dependencies to a pom. This mapping is based
  * on the configuration the dependencies belong to.
  *
  * @author Hans Dockter
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/file/CopySpec.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/file/CopySpec.java
index 872036c..7af8266 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/file/CopySpec.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/file/CopySpec.java
@@ -68,7 +68,7 @@ import java.util.regex.Pattern;
  */
 public interface CopySpec extends CopySourceSpec, CopyProcessingSpec, PatternFilterable {
     /**
-     * Returns true if this CopySpec uses case-sensitive pattern matching. The default is true.
+     * Specifies whether case-sensitive pattern matching should be used.
      *
      * @return true for case-sensitive matching.
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/initialization/Settings.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/initialization/Settings.java
index e2189b6..7401245 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/initialization/Settings.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/initialization/Settings.java
@@ -23,7 +23,7 @@ import org.gradle.api.invocation.Gradle;
 import java.io.File;
 
 /**
- * <p><code>Settings</code> declares the configuration required to instantiate and evaluate the hierarchy of {@link
+ * <p>Declares the configuration required to instantiate and configure the hierarchy of {@link
  * org.gradle.api.Project} instances which are to participate in a build.</p>
  *
  * <p>There is a one-to-one correspondence between a <code>Settings</code> instance and a <code>{@value
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/AutoCreateDomainObjectContainerDelegate.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/AutoCreateDomainObjectContainerDelegate.groovy
index 8b8b570..81f230c 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/AutoCreateDomainObjectContainerDelegate.groovy
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/AutoCreateDomainObjectContainerDelegate.groovy
@@ -27,6 +27,7 @@ class AutoCreateDomainObjectContainerDelegate {
         this.owner = owner
     }
 
+    @SuppressWarnings("EmptyCatchBlock")
     public Object invokeMethod(String name, Object params) {
         boolean isTopLevelCall = !configuring.get()
         configuring.set(true)
@@ -54,6 +55,7 @@ class AutoCreateDomainObjectContainerDelegate {
         }
     }
 
+    @SuppressWarnings("EmptyCatchBlock")
     public Object get(String name) {
         if (delegate.hasProperty(name)) {
             return delegate.getProperty(name)
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy
index 8e2d099..dd37262 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy
@@ -57,7 +57,10 @@ class DefaultIsolatedAntBuilder implements IsolatedAntBuilder {
         Map<String, Object> classloadersForPath = classloaders[normalisedClasspath]
         ClassLoader antLoader
         ClassLoader gradleLoader
-        if (!classloadersForPath) {
+        if (classloadersForPath) {
+            antLoader = classloadersForPath.antLoader
+            gradleLoader = classloadersForPath.gradleLoader
+        } else {
             // Need tools.jar for compile tasks
             List<File> fullClasspath = normalisedClasspath
             File toolsJar = Jvm.current().toolsJar
@@ -77,9 +80,6 @@ class DefaultIsolatedAntBuilder implements IsolatedAntBuilder {
             gradleLoader = new URLClassLoader(gradleCoreUrls, new MultiParentClassLoader(antLoader, loggingLoader))
 
             classloaders[normalisedClasspath] = [antLoader: antLoader, gradleLoader: gradleLoader]
-        } else {
-            antLoader = classloadersForPath.antLoader
-            gradleLoader = classloadersForPath.gradleLoader
         }
 
         ClassLoader originalLoader = Thread.currentThread().contextClassLoader
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/invocation/Gradle.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/invocation/Gradle.java
index b60d90d..39deb07 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/invocation/Gradle.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/invocation/Gradle.java
@@ -25,10 +25,9 @@ import org.gradle.api.execution.TaskExecutionGraph;
 import java.io.File;
 
 /**
- * <p>A {@code Gradle} represents an invocation of Gradle.</p>
+ * <p>Represents an invocation of Gradle.</p>
  *
- * <p>You can obtain a {@code Gradle} instance by calling {@link Project#getGradle()}. In your build file you can use
- * {@code gradle} to access it.</p>
+ * <p>You can obtain a {@code Gradle} instance by calling {@link Project#getGradle()}.</p>
  */
 public interface Gradle {
     /**
@@ -182,7 +181,7 @@ public interface Gradle {
      *
      * <li>{@link org.gradle.api.logging.StandardOutputListener}
      *
-     * <li>org.gradle.api.tasks.testing.TestListener
+     * <li>{@link org.gradle.api.tasks.testing.TestListener}
      *
      * </ul>
      *
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/AbstractCopyTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/AbstractCopyTask.java
index e619e09..0fed181 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/AbstractCopyTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/AbstractCopyTask.java
@@ -54,6 +54,10 @@ public abstract class AbstractCopyTask extends ConventionTask implements CopySpe
         return null;
     }
 
+    /**
+     * Returns the source files for this task.
+     * @return The source files. Never returns null.
+     */
     @InputFiles @SkipWhenEmpty @Optional
     public FileCollection getSource() {
         return getCopyAction().hasSource() ? getCopyAction().getAllSource() : getDefaultSource();
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Copy.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Copy.java
index 4ee30e9..40730a3 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Copy.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Copy.java
@@ -23,25 +23,24 @@ import org.gradle.api.internal.file.copy.FileCopySpecVisitor;
 import java.io.File;
 
 /**
- * Copies files into a destination directory.  This task can also rename and filter files as it copies.
- * The task implements {@link org.gradle.api.file.CopySpec CopySpec} for specifying
- * what to copy.
- * <p>
- * Examples:
+ * Copies files into a destination directory.  This task can also rename and filter files as it copies. The task
+ * implements {@link org.gradle.api.file.CopySpec CopySpec} for specifying what to copy.
+ *
+ * <p> Examples:
  * <pre>
- * task(mydoc, type:Copy) {
+ * task mydoc(type:Copy) {
  *    from 'src/main/doc'
  *    into 'build/target/doc'
  * }
  *
- * task(initconfig, type:Copy) {
+ * task initconfig(type:Copy) {
  *    from('src/main/config') {
  *       include '**/*.properties'
  *       include '**/*.xml'
  *       filter(ReplaceTokens, tokens:[version:'2.3.1'])
  *    }
  *    from('src/main/config') {
- *       exclude '**/*.properties', '**/*.xml'  
+ *       exclude '**/*.properties', '**/*.xml'
  *    }
  *    from('src/main/languages') {
  *       rename 'EN_US_(*.)', '$1'
@@ -50,6 +49,7 @@ import java.io.File;
  *    exclude '**/*.bak'
  * }
  * </pre>
+ *
  * @author Steve Appling
  */
 public class Copy extends AbstractCopyTask {
@@ -78,11 +78,21 @@ public class Copy extends AbstractCopyTask {
         this.copyAction = copyAction;
     }
 
+    /**
+     * Returns the directory to copy files into.
+     *
+     * @return The destination dir.
+     */
     @OutputDirectory
     public File getDestinationDir() {
         return getCopyAction().getDestinationDir();
     }
 
+    /**
+     * Sets the directory to copy files into. This is the same as calling {@link #into(Object)} on this task.
+     *
+     * @param destinationDir The destination directory. Must not be null.
+     */
     public void setDestinationDir(File destinationDir) {
         into(destinationDir);
     }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Delete.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Delete.java
index 5d9d49d..7794109 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Delete.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Delete.java
@@ -64,7 +64,7 @@ public class Delete extends ConventionTask {
     }
 
     /**
-     * Adds some files to be deleted by this task.
+     * Adds some files to be deleted by this task. The given targets are evaluated as for {@link org.gradle.api.Project#files(Object...)}.
      *
      * @param targets Any type of object accepted by {@link org.gradle.api.Project#files(Object...)}
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Exec.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Exec.java
index a09a73a..812c910 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Exec.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Exec.java
@@ -104,6 +104,20 @@ public class Exec extends ConventionTask implements ExecSpec {
     /**
      * {@inheritDoc}
      */
+    public void setCommandLine(Iterable<?> args) {
+        execAction.setCommandLine(args);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setCommandLine(Object... args) {
+        execAction.setCommandLine(args);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public String getExecutable() {
         return execAction.getExecutable();
     }
@@ -209,6 +223,13 @@ public class Exec extends ConventionTask implements ExecSpec {
     /**
      * {@inheritDoc}
      */
+    public OutputStream getStandardOutput() {
+        return execAction.getStandardOutput();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public Exec setErrorOutput(OutputStream outputStream) {
         execAction.setErrorOutput(outputStream);
         return this;
@@ -217,6 +238,13 @@ public class Exec extends ConventionTask implements ExecSpec {
     /**
      * {@inheritDoc}
      */
+    public OutputStream getErrorOutput() {
+        return execAction.getErrorOutput();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public ExecSpec setIgnoreExitValue(boolean ignoreExitValue) {
         execAction.setIgnoreExitValue(ignoreExitValue);
         return this;
@@ -234,7 +262,9 @@ public class Exec extends ConventionTask implements ExecSpec {
     }
 
     /**
-     * Returns the ExecResult object for the command run by this task. Returns null if the task has not been executed yet.
+     * Returns the result for the command run by this task. Returns {@code null} if this task has not been executed yet.
+     *
+     * @return The result. Returns {@code null} if this task has not been executed yet.
      */
     public ExecResult getExecResult() {
         return execResult;
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GeneratorTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GeneratorTask.java
index 446322d..7bee1e2 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GeneratorTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GeneratorTask.java
@@ -72,7 +72,7 @@ public class GeneratorTask<T> extends ConventionTask {
 
     /**
      * The input file to load the initial configuration from. Defaults to the output file. If the specified input file
-     * does not exist, this task uses a default initial configuration.
+     * does not exist, this task uses some default initial configuration.
      *
      * @return The input file.
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GradleBuild.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GradleBuild.java
index 11ee553..ecde020 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GradleBuild.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/GradleBuild.java
@@ -31,6 +31,7 @@ public class GradleBuild extends ConventionTask {
 
     public GradleBuild() {
         this.startParameter = getProject().getGradle().getStartParameter().newBuild();
+        startParameter.setCurrentDir(getProject().getProjectDir());
     }
 
     /**
@@ -52,7 +53,7 @@ public class GradleBuild extends ConventionTask {
     }
 
     /**
-     * Returns the project directory for the build.
+     * Returns the project directory for the build. Defaults to the project directory.
      *
      * @return The project directory. Never returns null.
      */
@@ -70,7 +71,8 @@ public class GradleBuild extends ConventionTask {
     }
 
     /**
-     * Returns the build file that should be used for this build.
+     * Returns the build file that should be used for this build. Defaults to {@value
+     * org.gradle.api.Project#DEFAULT_BUILD_FILE} in the project directory.
      *
      * @return The build file. May be null.
      */
@@ -88,7 +90,7 @@ public class GradleBuild extends ConventionTask {
     }
 
     /**
-     * Returns the sequence of tasks that should be executed for this build.
+     * Returns the tasks that should be executed for this build.
      *
      * @return The sequence. May be empty. Never returns null.
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/JavaExec.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/JavaExec.java
index a5ccb64..4398a15 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/JavaExec.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/JavaExec.java
@@ -32,7 +32,7 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * Executes a Java application.
+ * Executes a Java application in a child process.
  *
  * @author Hans Dockter
  */
@@ -372,6 +372,13 @@ public class JavaExec extends ConventionTask implements JavaExecSpec {
     /**
      * {@inheritDoc}
      */
+    public OutputStream getStandardOutput() {
+        return javaExecHandleBuilder.getStandardOutput();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public JavaExec setErrorOutput(OutputStream outputStream) {
         javaExecHandleBuilder.setErrorOutput(outputStream);
         return this;
@@ -380,6 +387,13 @@ public class JavaExec extends ConventionTask implements JavaExecSpec {
     /**
      * {@inheritDoc}
      */
+    public OutputStream getErrorOutput() {
+        return javaExecHandleBuilder.getErrorOutput();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
     public JavaExecSpec setIgnoreExitValue(boolean ignoreExitValue) {
         javaExecHandleBuilder.setIgnoreExitValue(ignoreExitValue);
         return this;
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Sync.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Sync.java
index cd9583a..7f4e22a 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Sync.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Sync.java
@@ -24,7 +24,7 @@ import org.gradle.api.internal.file.copy.SyncCopySpecVisitor;
 import java.io.File;
 
 /**
- * Synchronises the contents of a destination directory with some source.
+ * Synchronises the contents of a destination directory with some source directories and files.
  */
 public class Sync extends AbstractCopyTask {
     private FileCopyActionImpl action;
@@ -39,8 +39,22 @@ public class Sync extends AbstractCopyTask {
         return action;
     }
 
+    /**
+     * Returns the directory to copy files into.
+     *
+     * @return The destination dir.
+     */
     @OutputDirectory
     public File getDestinationDir() {
         return getCopyAction().getDestinationDir();
     }
+
+    /**
+     * Sets the directory to copy files into. This is the same as calling {@link #into(Object)} on this task.
+     *
+     * @param destinationDir The destination directory. Must not be null.
+     */
+    public void setDestinationDir(File destinationDir) {
+        into(destinationDir);
+    }
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Upload.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Upload.java
index 02d91c1..912bf11 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Upload.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/Upload.java
@@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory;
 import java.io.File;
 
 /**
- * Uploads the artifacts of a configuration to a set of repositories.
+ * Uploads the artifacts of a {@link Configuration} to a set of repositories.
  * 
  * @author Hans Dockter
  */
@@ -56,6 +56,9 @@ public class Upload extends ConventionTask {
         configuration.publish(repositories.getResolvers(), isUploadDescriptor() ? getDescriptorDestination() : null);
     }
 
+    /**
+     * Specifies whether the dependency descriptor should be uploaded.
+     */
     public boolean isUploadDescriptor() {
         return uploadDescriptor;
     }
@@ -64,6 +67,9 @@ public class Upload extends ConventionTask {
         this.uploadDescriptor = uploadDescriptor;
     }
 
+    /**
+     * Returns the path to generate the dependency descriptor to.
+     */
     public File getDescriptorDestination() {
         return descriptorDestination;
     }
@@ -72,6 +78,9 @@ public class Upload extends ConventionTask {
         this.descriptorDestination = descriptorDestination;
     }
 
+    /**
+     * Returns the repositories to upload to.
+     */
     public RepositoryHandler getRepositories() {
         return repositories;
     }
@@ -80,6 +89,9 @@ public class Upload extends ConventionTask {
         this.repositories = repositories;
     }
 
+    /**
+     * Returns the configuration to upload.
+     */
     public Configuration getConfiguration() {
         return configuration;
     }
@@ -88,6 +100,9 @@ public class Upload extends ConventionTask {
         this.configuration = configuration;
     }
 
+    /**
+     * Configures the set of repositories to upload to.
+     */
     public RepositoryHandler repositories(Closure configureClosure) {
         return ConfigureUtil.configure(configureClosure, repositories);
     }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/VerificationTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/VerificationTask.java
index a545f3b..99b57ab 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/VerificationTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/VerificationTask.java
@@ -20,7 +20,7 @@ package org.gradle.api.tasks;
  */
 public interface VerificationTask {
     /**
-     * Specify whether the build should break when the verifications performed by this task fail.
+     * Specifies whether the build should break when the verifications performed by this task fail.
      *
      * @param ignoreFailures false to break the build on failure, true to ignore the failures. The default is false.
      * @return this
@@ -28,7 +28,7 @@ public interface VerificationTask {
     VerificationTask setIgnoreFailures(boolean ignoreFailures);
 
     /**
-     * Returns whether the build should break when the verifications performed by this task fail.
+     * Specifies whether the build should break when the verifications performed by this task fail.
      *
      * @return false, when the build should break on failure, true when the failures should be ignored.
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/AbstractArchiveTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/AbstractArchiveTask.java
index 3618ddf..d0e516a 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/AbstractArchiveTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/AbstractArchiveTask.java
@@ -37,7 +37,7 @@ public abstract class AbstractArchiveTask extends AbstractCopyTask {
 
     /**
      * Returns the archive name. If the name has not been explicitly set, the pattern for the name is:
-     * [baseName]-[appendix]-[version]-[classifier].[extension]
+     * <code>[baseName]-[appendix]-[version]-[classifier].[extension]</code>
      *
      * @return the archive name.
      */
@@ -73,7 +73,7 @@ public abstract class AbstractArchiveTask extends AbstractCopyTask {
     }
 
     /**
-     * The path where the archive is constructed. The path is simply the destinationDir plus the archiveName.
+     * The path where the archive is constructed. The path is simply the {@code destinationDir} plus the {@code archiveName}.
      *
      * @return a File object with the path to the archive
      */
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/Tar.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/Tar.java
index fb522c3..87610dd 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/Tar.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/bundling/Tar.java
@@ -49,7 +49,7 @@ public class Tar extends AbstractArchiveTask {
     }
 
     /**
-     * Returns the compression to use for this archive. The default is {@link org.gradle.api.tasks.bundling.Compression#NONE}.
+     * Returns the compression to use for this archive.
      * @return The compression. Never returns null.
      */
     public Compression getCompression() {
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/AbstractReportTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/AbstractReportTask.java
index 07ac946..82b1751 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/AbstractReportTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/AbstractReportTask.java
@@ -78,17 +78,19 @@ public abstract class AbstractReportTask extends ConventionTask {
     protected abstract void generate(Project project) throws IOException;
 
     /**
-     * Returns the file which the report will be written to. When set to null, the report is written to stdout.
+     * Returns the file which the report will be written to. When set to {@code null}, the report is written to {@code System.out}.
+     * Defaults to {@code null}.
      *
      * @return The output file. May be null.
      */
-    @OutputFile @Optional
+    @OutputFile
+    @Optional
     public File getOutputFile() {
         return outputFile;
     }
 
     /**
-     * Sets the file which the report will be written to. Set this to null to write the report to stdout.
+     * Sets the file which the report will be written to. Set this to {@code null} to write the report to {@code System.out}.
      *
      * @param outputFile The output file. May be null.
      */
@@ -96,10 +98,21 @@ public abstract class AbstractReportTask extends ConventionTask {
         this.outputFile = outputFile;
     }
 
+    /**
+     * Returns the set of project to generate this report for. By default, the report is generated for the task's
+     * containing project.
+     *
+     * @return The set of files.
+     */
     public Set<Project> getProjects() {
         return projects;
     }
 
+    /**
+     * Specifies the set of projects to generate this report for.
+     *
+     * @param projects The set of projects. Must not be null.
+     */
     public void setProjects(Set<Project> projects) {
         this.projects = projects;
     }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/DependencyReportTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/DependencyReportTask.java
index cd6178c..6cfab91 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/DependencyReportTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/DependencyReportTask.java
@@ -28,9 +28,9 @@ import java.util.SortedSet;
 import java.util.TreeSet;
 
 /**
- * Displays the dependency tree for a project. Can be configured to output to a file,
- * and to optionally output a graphviz compatible "dot" graph. This task is used when you execute the dependency list
- * command-line option.
+ * Displays the dependency tree for a project. Can be configured to output to a file, and to optionally output a
+ * graphviz compatible "dot" graph. An instance of this type is used when you execute the {@code dependencies} task from
+ * the command-line.
  *
  * @author Phil Messenger
  */
@@ -52,12 +52,11 @@ public class DependencyReportTask extends AbstractReportTask {
     }
 
     public void generate(Project project) throws IOException {
-        SortedSet<Configuration> sortedConfigurations = new TreeSet<Configuration>(
-                new Comparator<Configuration>() {
-                    public int compare(Configuration conf1, Configuration conf2) {
-                        return conf1.getName().compareTo(conf2.getName());
-                    }
-                });
+        SortedSet<Configuration> sortedConfigurations = new TreeSet<Configuration>(new Comparator<Configuration>() {
+            public int compare(Configuration conf1, Configuration conf2) {
+                return conf1.getName().compareTo(conf2.getName());
+            }
+        });
         sortedConfigurations.addAll(getConfigurations(project));
         for (Configuration configuration : sortedConfigurations) {
             renderer.startConfiguration(configuration);
@@ -71,14 +70,19 @@ public class DependencyReportTask extends AbstractReportTask {
     }
 
     /**
-     * Returns the configurations to use to build a report. If unset, all project configurations will be used.
+     * Returns the configurations to generate the report for. Default to all configurations of this task's containing
+     * project.
+     *
+     * @return the configurations.
      */
     public Set<Configuration> getConfigurations() {
         return configurations;
     }
 
     /**
-     * Set the configurations to use to build a report. If unset, all project configurations will be used.
+     * Sets the configurations to generate the report for.
+     *
+     * @param configurations The configuration. Must not be null.
      */
     public void setConfigurations(Set<Configuration> configurations) {
         this.configurations = configurations;
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTask.java
index 0952689..d4a1dbd 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTask.java
@@ -17,16 +17,15 @@ package org.gradle.api.tasks.diagnostics;
 
 import org.apache.commons.lang.StringUtils;
 import org.gradle.api.Action;
-import org.gradle.api.DefaultTask;
 import org.gradle.api.Project;
-import org.gradle.api.tasks.TaskAction;
 import org.gradle.api.tasks.diagnostics.internal.GraphRenderer;
+import org.gradle.api.tasks.diagnostics.internal.TextReportRenderer;
 import org.gradle.configuration.ImplicitTasksConfigurer;
 import org.gradle.initialization.BuildClientMetaData;
 import org.gradle.logging.StyledTextOutput;
-import org.gradle.logging.StyledTextOutputFactory;
 import org.gradle.util.GUtil;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -34,18 +33,24 @@ import java.util.List;
 import static org.gradle.logging.StyledTextOutput.Style.*;
 
 /**
- * <p>Displays a list of projects in the build. It is used when you use the project list command-line option.</p>
+ * <p>Displays a list of projects in the build. An instance of this type is used when you execute the {@code projects}
+ * task from the command-line.</p>
  */
-public class ProjectReportTask extends DefaultTask {
-    private StyledTextOutput textOutput = getServices().get(StyledTextOutputFactory.class).create(ProjectReportTask.class);
+public class ProjectReportTask extends AbstractReportTask {
+    private TextReportRenderer renderer = new TextReportRenderer();
 
-    @TaskAction
-    void listProjects() {
+    @Override
+    protected TextReportRenderer getRenderer() {
+        return renderer;
+    }
+
+    @Override
+    protected void generate(Project project) throws IOException {
         BuildClientMetaData metaData = getServices().get(BuildClientMetaData.class);
-        Project project = getProject();
 
-        textOutput.println();
-        render(project, new GraphRenderer(textOutput), true);
+        StyledTextOutput textOutput = getRenderer().getTextOutput();
+
+        render(project, new GraphRenderer(textOutput), true, textOutput);
         if (project.getChildProjects().isEmpty()) {
             textOutput.withStyle(Info).text("No sub-projects");
             textOutput.println();
@@ -53,35 +58,39 @@ public class ProjectReportTask extends DefaultTask {
 
         textOutput.println();
         textOutput.text("To see a list of the tasks of a project, run ");
-        metaData.describeCommand(textOutput.withStyle(UserInput), String.format("<project-path>:%s", ImplicitTasksConfigurer.TASKS_TASK));
+        metaData.describeCommand(textOutput.withStyle(UserInput), String.format("<project-path>:%s",
+                ImplicitTasksConfigurer.TASKS_TASK));
         textOutput.println();
 
         textOutput.text("For example, try running ");
         Project exampleProject = project.getChildProjects().isEmpty() ? project : getChildren(project).get(0);
-        metaData.describeCommand(textOutput.withStyle(UserInput), exampleProject.absoluteProjectPath(ImplicitTasksConfigurer.TASKS_TASK));
+        metaData.describeCommand(textOutput.withStyle(UserInput), exampleProject.absoluteProjectPath(
+                ImplicitTasksConfigurer.TASKS_TASK));
         textOutput.println();
 
         if (project != project.getRootProject()) {
             textOutput.println();
             textOutput.text("To see a list of all the projects in this build, run ");
-            metaData.describeCommand(textOutput.withStyle(UserInput), project.getRootProject().absoluteProjectPath(ImplicitTasksConfigurer.PROJECTS_TASK));
+            metaData.describeCommand(textOutput.withStyle(UserInput), project.getRootProject().absoluteProjectPath(
+                    ImplicitTasksConfigurer.PROJECTS_TASK));
             textOutput.println();
         }
     }
 
-    private void render(final Project project, GraphRenderer renderer, boolean lastChild) {
+    private void render(final Project project, GraphRenderer renderer, boolean lastChild,
+                        final StyledTextOutput textOutput) {
         renderer.visit(new Action<StyledTextOutput>() {
             public void execute(StyledTextOutput styledTextOutput) {
                 styledTextOutput.text(StringUtils.capitalize(project.toString()));
                 if (GUtil.isTrue(project.getDescription())) {
-                    getTextOutput().withStyle(Description).format(" - %s", project.getDescription());
+                    textOutput.withStyle(Description).format(" - %s", project.getDescription());
                 }
             }
         }, lastChild);
         renderer.startChildren();
         List<Project> children = getChildren(project);
         for (Project child : children) {
-            render(child, renderer, child == children.get(children.size() - 1));
+            render(child, renderer, child == children.get(children.size() - 1), textOutput);
         }
         renderer.completeChildren();
     }
@@ -91,12 +100,4 @@ public class ProjectReportTask extends DefaultTask {
         Collections.sort(children);
         return children;
     }
-
-    public StyledTextOutput getTextOutput() {
-        return textOutput;
-    }
-
-    public void setTextOutput(StyledTextOutput textOutput) {
-        this.textOutput = textOutput;
-    }
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/PropertyReportTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/PropertyReportTask.java
index b86ce4c..bdfc43e 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/PropertyReportTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/PropertyReportTask.java
@@ -24,7 +24,8 @@ import java.util.Map;
 import java.util.TreeMap;
 
 /**
- * Displays the properties of a project. This task is used when you execute the property list command-line option.
+ * Displays the properties of a project. An instance of this type is used when you execute the {@code properties} task
+ * from the command-line.
  */
 public class PropertyReportTask extends AbstractReportTask {
     private PropertyReportRenderer renderer = new PropertyReportRenderer();
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
index aa7f8ed..b0fb3e2 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/diagnostics/TaskReportTask.java
@@ -25,7 +25,8 @@ import org.gradle.util.GUtil;
 import java.io.IOException;
 
 /**
- * <p>Displays a list of tasks in the project. It is used when you use the task list command-line option.</p>
+ * <p>Displays a list of tasks in the project. An instance of this type is used when you execute the {@code tasks} task
+ * from the command-line.</p>
  */
 public class TaskReportTask extends AbstractReportTask {
     private TaskReportRenderer renderer = new TaskReportRenderer();
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternFilterable.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternFilterable.java
index 82366f4..736f30c 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternFilterable.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternFilterable.java
@@ -68,12 +68,16 @@ import groovy.lang.Closure;
 public interface PatternFilterable {
 
     /**
-     * Get the set of include patterns.
+     * Returns the set of include patterns.
+     *
+     * @return The include patterns. Returns an empty set when there are no include patterns.
      */
     Set<String> getIncludes();
 
     /**
-     * Get the set of exclude patterns.
+     * Returns the set of exclude patterns.
+     *
+     * @return The exclude patterns. Returns an empty set when there are no exclude patterns.
      */
     Set<String> getExcludes();
 
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternSet.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternSet.groovy
index 6a1f26f..6f15567 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternSet.groovy
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/tasks/util/PatternSet.groovy
@@ -66,7 +66,7 @@ class PatternSet implements AntBuilderAware, PatternFilterable {
         if (o == null || o.getClass() != getClass()) {
             return false
         }
-        return o.includes.equals(includes) && o.excludes.equals(excludes) && o.caseSensitive == caseSensitive
+        return o.includes == includes && o.excludes == excludes && o.caseSensitive == caseSensitive
     }
 
     def int hashCode() {
@@ -93,7 +93,7 @@ class PatternSet implements AntBuilderAware, PatternFilterable {
 
         boolean hasIncludes = includes || includeSpecs
         if (hasIncludes) {
-            List<Spec<FileTreeElement>> matchers = new ArrayList<Spec<FileTreeElement>>()
+            List<Spec<FileTreeElement>> matchers = []
             for (String include: includes) {
                 matchers.add(new RelativePathSpec(PatternMatcherFactory.getPatternMatcher(true, caseSensitive, include)))
             }
@@ -107,7 +107,7 @@ class PatternSet implements AntBuilderAware, PatternFilterable {
             return includeSpec
         }
 
-        List<Spec<FileTreeElement>> matchers = new ArrayList<Spec<FileTreeElement>>()
+        List<Spec<FileTreeElement>> matchers = []
         for (String exclude: allExcludes) {
             matchers.add(new RelativePathSpec(PatternMatcherFactory.getPatternMatcher(false, caseSensitive, exclude)))
         }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/BasicScript.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/BasicScript.groovy
index 7a59de6..1afd6fb 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/BasicScript.groovy
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/BasicScript.groovy
@@ -43,9 +43,9 @@ abstract class BasicScript extends org.gradle.groovy.scripts.Script implements o
     }
 
     void setProperty(String property, newValue) {
-        if ("metaClass".equals(property)) {
+        if ("metaClass" == property) {
             setMetaClass((MetaClass) newValue)
-        } else if ("scriptTarget".equals(property)) {
+        } else if ("scriptTarget" == property) {
             target = newValue
         } else {
             target."$property" = newValue
@@ -53,7 +53,7 @@ abstract class BasicScript extends org.gradle.groovy.scripts.Script implements o
     }
 
     def propertyMissing(String property) {
-        if ('out'.equals(property)) {
+        if ('out' == property) {
             System.out
         } else {
             target."$property"
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/messaging/remote/internal/TcpIncomingConnector.java b/subprojects/gradle-core/src/main/groovy/org/gradle/messaging/remote/internal/TcpIncomingConnector.java
index 1ceca32..615d5c2 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/messaging/remote/internal/TcpIncomingConnector.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/messaging/remote/internal/TcpIncomingConnector.java
@@ -88,20 +88,25 @@ public class TcpIncomingConnector implements IncomingConnector, AsyncStoppable {
 
         public void run() {
             try {
-                while (true) {
-                    SocketChannel socket = serverSocket.accept();
-                    InetSocketAddress remoteAddress = (InetSocketAddress) socket.socket().getRemoteSocketAddress();
-                    if (!localAddresses.contains(remoteAddress.getAddress())) {
-                        LOGGER.error("Cannot accept connection from remote address {}.", remoteAddress.getAddress());
+                try {
+                    while (true) {
+                        SocketChannel socket = serverSocket.accept();
+                        InetSocketAddress remoteAddress = (InetSocketAddress) socket.socket().getRemoteSocketAddress();
+                        if (!localAddresses.contains(remoteAddress.getAddress())) {
+                            LOGGER.error("Cannot accept connection from remote address {}.", remoteAddress.getAddress());
+                        }
+                        URI remoteUri = new URI(String.format("tcp://localhost:%d", remoteAddress.getPort()));
+                        LOGGER.debug("Accepted connection from {}.", remoteUri);
+                        action.execute(new ConnectEvent<Connection<Object>>(new SocketConnection<Object>(socket, localAddress, remoteUri, classLoader), localAddress, remoteUri));
                     }
-                    URI remoteUri = new URI(String.format("tcp://localhost:%d", remoteAddress.getPort()));
-                    LOGGER.debug("Accepted connection from {}.", remoteUri);
-                    action.execute(new ConnectEvent<Connection<Object>>(new SocketConnection<Object>(socket, localAddress, remoteUri, classLoader), localAddress, remoteUri));
+                } catch (ClosedChannelException e) {
+                    // Ignore
+                } catch (Exception e) {
+                    LOGGER.error("Could not accept remote connection.", e);
                 }
-            } catch (ClosedChannelException e) {
-                // Ignore
-            } catch (Exception e) {
-                LOGGER.error("Could not accept remote connection.", e);
+            } finally {
+                new CompositeStoppable(serverSocket).stop();
+                serverSockets.remove(serverSocket);
             }
         }
     }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/process/BaseExecSpec.java b/subprojects/gradle-core/src/main/groovy/org/gradle/process/BaseExecSpec.java
index be8fdb5..e45485c 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/process/BaseExecSpec.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/process/BaseExecSpec.java
@@ -30,13 +30,12 @@ public interface BaseExecSpec extends ProcessForkOptions {
      * thrown in case of such an exit value.
      *
      * @param ignoreExitValue whether to ignore the exit value or not
-     *
      * @return this
      */
     BaseExecSpec setIgnoreExitValue(boolean ignoreExitValue);
 
     /**
-     * Returns whether an exit value different from zero should be ignored. In case it is not ignored, an exception is
+     * Specifies whether an exit value different from zero should be ignored. In case it is not ignored, an exception is
      * thrown in case of such an exit value. Defaults to <code>false</code>.
      */
     boolean isIgnoreExitValue();
@@ -44,40 +43,56 @@ public interface BaseExecSpec extends ProcessForkOptions {
     /**
      * Sets the standard input stream for the process executing the command. The stream is closed after the process
      * completes.
-     * 
-     * @param inputStream The standard input stream for the command process.
      *
+     * @param inputStream The standard input stream for the process. Must not be null.
      * @return this
      */
     BaseExecSpec setStandardInput(InputStream inputStream);
 
     /**
-     * Returns the standard input stream for the process executing the command.
+     * Returns the standard input stream for the process executing the command. The stream is closed after the process
+     * completes. Defaults to an empty stream.
+     *
+     * @return The standard input stream.
      */
     InputStream getStandardInput();
 
     /**
-     * Sets the standard output stream for the process executing the command. The stream is closed after the process
-     * completes.
-     *
-     * @param outputStream The standard output stream for the command process.
+     * Sets the output stream to consume standard output from the process executing the command. The stream is closed
+     * after the process completes.
      *
+     * @param outputStream The standard output stream for the process. Must not be null.
      * @return this
      */
     BaseExecSpec setStandardOutput(OutputStream outputStream);
 
     /**
-     * Sets the error output stream for the process executing the command. The stream is closed after the process
-     * completes.
+     * Returns the output stream to consume standard output from the process executing the command. Defaults to {@code
+     * System.out}.
      *
-     * @param outputStream The standard output error stream for the command process.
+     * @return The output stream
+     */
+    OutputStream getStandardOutput();
+
+    /**
+     * Sets the output stream to consume standard error from the process executing the command. The stream is closed
+     * after the process completes.
      *
+     * @param outputStream The standard output error stream for the process. Must not be null.
      * @return this
      */
     BaseExecSpec setErrorOutput(OutputStream outputStream);
 
     /**
-     * Returns the command plus its arguments.
+     * Returns the output stream to consume standard error from the process executing the command. Default to {@code
+     * System.err}.
+     *
+     * @return The error output stream.
+     */
+    OutputStream getErrorOutput();
+
+    /**
+     * Returns the full command line, including the executable plus its arguments.
      */
     List<String> getCommandLine();
 }
\ No newline at end of file
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/process/ExecSpec.java b/subprojects/gradle-core/src/main/groovy/org/gradle/process/ExecSpec.java
index da845c9..83ca73a 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/process/ExecSpec.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/process/ExecSpec.java
@@ -24,50 +24,61 @@ import java.util.List;
  */
 public interface ExecSpec extends BaseExecSpec {
     /**
-     * Sets the command plus the args to be executed.
+     * Sets the full command line, including the executable to be executed plus its arguments.
+     *
      * @param args the command plus the args to be executed
+     */
+    void setCommandLine(Object... args);
+
+    /**
+     * Sets the full command line, including the executable to be executed plus its arguments.
      *
+     * @param args the command plus the args to be executed
+     */
+    void setCommandLine(Iterable<?> args);
+
+    /**
+     * Sets the full command line, including the executable to be executed plus its arguments.
+     *
+     * @param args the command plus the args to be executed
      * @return this
      */
     ExecSpec commandLine(Object... args);
 
     /**
-     * Sets the command plus the args to be executed.
-     * @param args the command plus the args to be executed
+     * Sets the full command line, including the executable to be executed plus its arguments.
      *
+     * @param args the command plus the args to be executed
      * @return this
      */
     ExecSpec commandLine(Iterable<?> args);
 
     /**
-     * Adds args for the command to be executed.
+     * Adds arguments for the command to be executed.
      *
      * @param args args for the command
-     *
      * @return this
      */
     ExecSpec args(Object... args);
 
     /**
-     * Adds args for the command to be executed.
+     * Adds arguments for the command to be executed.
      *
      * @param args args for the command
-     *
      * @return this
      */
     ExecSpec args(Iterable<?> args);
 
     /**
-     * Sets the args for the command to be executed.
+     * Sets the arguments for the command to be executed.
      *
      * @param args args for the command
-     *
      * @return this
      */
     ExecSpec setArgs(Iterable<?> args);
 
     /**
-     * Returns the args for the command to be executed.
+     * Returns the arguments for the command to be executed. Defaults to an empty list.
      */
     List<String> getArgs();
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/AbstractExecHandleBuilder.java b/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/AbstractExecHandleBuilder.java
index ac4610d..717e949 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/AbstractExecHandleBuilder.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/AbstractExecHandleBuilder.java
@@ -67,6 +67,10 @@ public abstract class AbstractExecHandleBuilder extends DefaultProcessForkOption
         return this;
     }
 
+    public OutputStream getStandardOutput() {
+        return standardOutput;
+    }
+
     public AbstractExecHandleBuilder setErrorOutput(OutputStream outputStream) {
         if (outputStream == null) {
             throw new IllegalArgumentException("outputStream == null!");
@@ -75,6 +79,10 @@ public abstract class AbstractExecHandleBuilder extends DefaultProcessForkOption
         return this;
     }
 
+    public OutputStream getErrorOutput() {
+        return errorOutput;
+    }
+
     public boolean isIgnoreExitValue() {
         return ignoreExitValue;
     }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/ExecHandleBuilder.java b/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/ExecHandleBuilder.java
index 54c46d8..ba2cf14 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/ExecHandleBuilder.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/process/internal/ExecHandleBuilder.java
@@ -51,6 +51,14 @@ public class ExecHandleBuilder extends AbstractExecHandleBuilder implements Exec
         return this;
     }
 
+    public void setCommandLine(Object... args) {
+        commandLine(args);
+    }
+
+    public void setCommandLine(Iterable<?> args) {
+        commandLine(args);
+    }
+
     public ExecHandleBuilder args(Object... args) {
         if (args == null) {
             throw new IllegalArgumentException("args == null!");
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/GradleBuildTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/GradleBuildTest.groovy
index 74f828d..26a7c48 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/GradleBuildTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/GradleBuildTest.groovy
@@ -47,7 +47,9 @@ public class GradleBuildTest extends AbstractTaskTest {
 
     @Test
     void usesCopyOfCurrentBuildsStartParams() {
-        assertThat(task.startParameter, equalTo(project.gradle.startParameter.newBuild()))
+        def expectedStartParameter = project.gradle.startParameter.newBuild()
+        expectedStartParameter.currentDir = project.projectDir
+        assertThat(task.startParameter, equalTo(expectedStartParameter))
         task.tasks = ['a', 'b']
         assertThat(task.tasks, equalTo(['a', 'b']))
         assertThat(task.startParameter.taskNames, equalTo(['a', 'b']))
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTaskTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTaskTest.groovy
index 4a48fb7..0f5e256 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTaskTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/ProjectReportTaskTest.groovy
@@ -22,23 +22,26 @@ import org.gradle.util.HelperUtil
 import spock.lang.Specification
 
 class ProjectReportTaskTest extends Specification {
-    private final ProjectInternal project = HelperUtil.createRootProject()
+    final ProjectInternal project = HelperUtil.createRootProject()
+    final ProjectReportTask task = HelperUtil.createTask(ProjectReportTask, project)
+    final TestStyledTextOutput output = new TestStyledTextOutput().ignoreStyle()
+
+    def setup() {
+        task.renderer.output = output
+    }
 
     def rendersReportForRootProjectWithChildren() {
-        ProjectReportTask task = HelperUtil.createTask(ProjectReportTask, project)
         project.description = 'this is the root project'
         Project child1 = HelperUtil.createChildProject(project, "child1")
         child1.description = 'this is a subproject'
         HelperUtil.createChildProject(child1, "child1")
         HelperUtil.createChildProject(project, "child2")
-        task.textOutput = new TestStyledTextOutput().ignoreStyle()
 
         when:
-        task.listProjects()
+        task.generate(project)
 
         then:
-        task.textOutput.value == '''
-Root project 'test' - this is the root project
+        output.value == '''Root project 'test' - this is the root project
 +--- Project ':child1' - this is a subproject
 |    \\--- Project ':child1:child1'
 \\--- Project ':child2'
@@ -49,16 +52,13 @@ For example, try running gradle :child1:tasks
     }
 
     def rendersReportForRootProjectWithNoChildren() {
-        ProjectReportTask task = HelperUtil.createTask(ProjectReportTask, project)
         project.description = 'this is the root project'
-        task.textOutput = new TestStyledTextOutput().ignoreStyle()
 
         when:
-        task.listProjects()
+        task.generate(project)
 
         then:
-        task.textOutput.value == '''
-Root project 'test' - this is the root project
+        output.value == '''Root project 'test' - this is the root project
 No sub-projects
 
 To see a list of the tasks of a project, run gradle <project-path>:tasks
@@ -68,15 +68,12 @@ For example, try running gradle :tasks
 
     def rendersReportForNonRootProjectWithNoChildren() {
         Project child1 = HelperUtil.createChildProject(project, "child1")
-        ProjectReportTask task = HelperUtil.createTask(ProjectReportTask, child1)
-        task.textOutput = new TestStyledTextOutput().ignoreStyle()
 
         when:
-        task.listProjects()
+        task.generate(child1)
 
         then:
-        task.textOutput.value == '''
-Project ':child1'
+        output.value == '''Project ':child1'
 No sub-projects
 
 To see a list of the tasks of a project, run gradle <project-path>:tasks
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/util/LinePerThreadBufferingOutputStreamTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/util/LinePerThreadBufferingOutputStreamTest.groovy
index 7aa9491..647537a 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/util/LinePerThreadBufferingOutputStreamTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/util/LinePerThreadBufferingOutputStreamTest.groovy
@@ -30,7 +30,7 @@ class LinePerThreadBufferingOutputStreamTest extends MultithreadedTestCase {
         10.times {
             start {
                 100.times {
-                    outstr.write('write ' as byte[])
+                    outstr.write('write '.getBytes())
                     outstr.print(it)
                     outstr.println()
                 }
diff --git a/subprojects/gradle-docs/docs.gradle b/subprojects/gradle-docs/docs.gradle
index 343b7f6..f38c369 100644
--- a/subprojects/gradle-docs/docs.gradle
+++ b/subprojects/gradle-docs/docs.gradle
@@ -17,7 +17,7 @@
 import org.gradle.build.docs.UserGuideTransformTask
 import org.gradle.build.docs.ExtractSnippetsTask
 import org.gradle.build.docs.AssembleSamplesDocTask
-import org.gradle.build.docs.dsl.AssembleDslDocTask
+import org.gradle.build.docs.dsl.docbook.AssembleDslDocTask
 import org.gradle.build.docs.dsl.ExtractDslMetaDataTask
 
 apply plugin: 'base'
@@ -49,12 +49,13 @@ RemoteLocations remoteLocations = new RemoteLocations(version: version)
 srcDocsDir = file('src/docs')
 userguideSrcDir = new File(srcDocsDir, 'userguide')
 cssSrcDir = new File(srcDocsDir, 'css')
+dslSrcDir = new File(srcDocsDir, 'dsl')
 
 docsDir = file("$buildDir/docs")
 userguideDir = new File(docsDir, 'userguide')
 distDocsDir = new File(buildDir, 'distDocs')
 samplesDir = file("$buildDir/samples")
-docbookSrc = new File(project.buildDir, 'src/docbook')
+docbookSrc = new File(project.buildDir, 'src')
 samplesSrcDir = file('src/samples')
 websiteDocs = new File(buildDir, 'websiteDocs')
 
@@ -65,12 +66,13 @@ tasks.withType(Docbook2Xhtml).allObjects { task->
 }
 tasks.withType(UserGuideTransformTask).allObjects { task->
     task.classpath = configurations.userGuideTask
-    task.dependsOn samples
+    task.dependsOn samples, dslDocbook
     task.snippetsDir = samples.snippetsDir
+    task.linksFile = dslDocbook.linksFile
 }
 tasks.withType(AssembleDslDocTask).allObjects { task ->
     task.classpath = configurations.userGuideTask
-    task.classDocbookDir = new File(userguideSrcDir, 'dsl')
+    task.classDocbookDir = dslSrcDir
 }
 
 task samples(type: ExtractSnippetsTask) {
@@ -122,11 +124,12 @@ task dslMetaData(type: ExtractDslMetaDataTask) {
 }
 
 task dslDocbook(type: AssembleDslDocTask, dependsOn: [dslMetaData]) {
-    inputs.files fileTree(dir: userguideSrcDir, includes: ['dsl/*.xml'])
-    sourceFile = new File(userguideSrcDir, 'dsl/dsl.xml')
+    inputs.files fileTree(dir: dslSrcDir, includes: ['*.xml'])
+    sourceFile = new File(dslSrcDir, 'dsl.xml')
     classMetaDataFile = dslMetaData.destFile
-    pluginsMetaDataFile = new File(userguideSrcDir, 'dsl/plugins.xml')
+    pluginsMetaDataFile = new File(dslSrcDir, 'plugins.xml')
     destFile = new File(docbookSrc, 'dsl.xml')
+    linksFile = new File(docbookSrc, 'api-links.bin')
 }
 
 task dslStandaloneDocbook(type: UserGuideTransformTask, dependsOn: [dslDocbook]) {
@@ -136,6 +139,7 @@ task dslStandaloneDocbook(type: UserGuideTransformTask, dependsOn: [dslDocbook])
     destFile = new File(docbookSrc, 'dsl-standalone.xml')
     javadocUrl = '../javadoc'
     groovydocUrl = '../groovydoc'
+    dsldocUrl = '.'
     websiteUrl = 'http://www.gradle.org'
 }
 
@@ -146,6 +150,9 @@ task dslHtml(type: Docbook2Xhtml, dependsOn: dslStandaloneDocbook) {
     resources = fileTree {
         from cssSrcDir
         include '*.css'
+    } + fileTree {
+        from dslSrcDir
+        include '*.js'
     }
 }
 
@@ -156,6 +163,7 @@ task userguideDocbook(type: UserGuideTransformTask, dependsOn: [samples, samples
     destFile = new File(docbookSrc, 'userguide.xml')
     javadocUrl = '../javadoc'
     groovydocUrl = '../groovydoc'
+    dsldocUrl = '../dsl'
     websiteUrl = 'http://www.gradle.org'
 }
 
@@ -167,6 +175,7 @@ task remoteUserguideDocbook(type: UserGuideTransformTask, dependsOn: samples) {
     doFirst {
         javadocUrl = remoteLocations.javadocUrl
         groovydocUrl = remoteLocations.groovydocUrl
+        dsldocUrl = remoteLocations.dsldocUrl
         websiteUrl = 'http://www.gradle.org'
     }
 }
@@ -248,7 +257,7 @@ task checkstyleApi(type: Checkstyle) {
 
 task groovydoc(type: Groovydoc) {
     group = 'documentation'
-    source groovyProjects().collect {project -> project.sourceSets.main.groovy }
+    source groovyProjects().collect {project -> project.sourceSets.main.groovy + project.sourceSets.main.java }
     destinationDir = new File(docsDir, 'groovydoc')
     includes = javadoc.includes
     excludes = javadoc.excludes
@@ -265,6 +274,7 @@ task userguideFragmentSrc(type: UserGuideTransformTask, dependsOn: [userguideSty
     doFirst {
         javadocUrl = remoteLocations.javadocUrl
         groovydocUrl = remoteLocations.groovydocUrl
+        dsldocUrl = remoteLocations.dsldocUrl
         websiteUrl = 'http://www.gradle.org'
     }
 }
@@ -284,6 +294,7 @@ task websiteUserguideSrc(type: UserGuideTransformTask, dependsOn: [userguideStyl
     doFirst {
         javadocUrl = remoteLocations.javadocUrl
         groovydocUrl = remoteLocations.groovydocUrl
+        dsldocUrl = remoteLocations.dsldocUrl
         websiteUrl = ''
     }
 }
@@ -310,7 +321,7 @@ task websiteProperties {
         def properties = new Properties()
         properties.version = version.toString()
         propertiesFile.parentFile.mkdirs()
-        propertiesFile.withWriter { writer -> properties.store(writer, 'documentation version properties') }
+        propertiesFile.withOutputStream { outputStream -> properties.store(outputStream, 'documentation version properties') }
     }
 }
 
@@ -379,6 +390,10 @@ class RemoteLocations {
     String getGroovydocUrl() {
         "$GRADLE_ORG_URL/${getDocsRemoteDir()}/groovydoc"
     }
+
+    String getDsldocUrl() {
+        "$GRADLE_ORG_URL/${getDocsRemoteDir()}/dsl"
+    }
 }
 
 class Docbook2Xhtml extends SourceTask {
diff --git a/subprojects/gradle-docs/src/docs/css/base.css b/subprojects/gradle-docs/src/docs/css/base.css
index 5fc5178..bc82563 100644
--- a/subprojects/gradle-docs/src/docs/css/base.css
+++ b/subprojects/gradle-docs/src/docs/css/base.css
@@ -5,8 +5,8 @@
 
 html {
     margin: 0;
-    height: 100%;
-    min-height: 100%
+    /*height: 100%;*/
+    /*min-height: 100%*/
 }
 
 body {
diff --git a/subprojects/gradle-docs/src/docs/css/dsl.css b/subprojects/gradle-docs/src/docs/css/dsl.css
index 47aeb7f..bc7bbc6 100644
--- a/subprojects/gradle-docs/src/docs/css/dsl.css
+++ b/subprojects/gradle-docs/src/docs/css/dsl.css
@@ -1,14 +1,22 @@
 
 .sidebar {
+    margin-top: 2em;
+    margin-left: 1.8em;
+    margin-right: 1.4em;
     position: absolute;
     top: 0;
     left: 0;
-    height: 100%;
-    width: 7em;
-    overflow: auto;
-    padding-top: 2em;
-    padding-left: 2em;
-    padding-right: 2em;
+    width: 13em;
+}
+
+.content {
+    margin-top: 2em;
+    margin-bottom: 2em;
+    margin-left: 4em;
+    margin-right: 4em;
+    position: absolute;
+    top: 0;
+    left: 14.6em;
 }
 
 .sidebar ul {
@@ -22,15 +30,87 @@
 
 .sidebar li.sidebarHeading {
     margin-top: 1.4em;
-    color: #a2a2a2;
+    margin-bottom: 0.4em;
+    font-weight: bold;
+    color: #505050;
 }
 
-.content {
-    position: absolute;
-    top: 0;
-    left: 13em;
+.sidebar li.selected {
+    font-weight: bold;
+    font-size: 110%;
+    color: #5283a1;
+    /*color: #505050;*/
+    background-color: #ebf4f7;
+    border: solid #c3d9e6 1px;
+    padding-top: 0.1em;
+    padding-bottom: 0.1em;
+    margin-left: -0.7em;
+    padding-left: 0.7em;
+    -webkit-border-radius: 2px;
+    -moz-border-radius: 2px;
+    border-radius: 2px;
+}
+
+.sidebar ul.sections {
+    padding-left: 1em;
 }
 
 .book .titlepage .releaseinfo {
     color: #666666;
 }
+
+.segmentedlist {
+    margin-top: 1.6em;
+    margin-bottom: 1.6em;
+}
+
+.segmentedlist table, .table table {
+    border: solid #d0d0d0 1px;
+    border-collapse: collapse;
+    margin-left: -0.8em;
+    margin-right: -0.8em;
+}
+
+.segmentedlist th {
+    padding-left: 0.8em;
+    padding-right: 0.8em;
+    padding-top: 0.3em;
+    padding-bottom: 0.3em;
+    color: #505050;
+}
+
+.segmentedlist td {
+    padding-left: 0.8em;
+    padding-right: 0.8em;
+    padding-top: 0.3em;
+    padding-bottom: 0.3em;
+}
+
+.segmentedlist dt {
+    font-weight: bold;
+}
+
+.signature {
+    background-color: #f5f5f5;
+    border: solid #e7e7e7 1px;
+    color: #666666;
+    width: auto;
+    margin-right: -0.8em;
+    padding-right: 0.8em;
+    margin-left: -0.8em;
+    padding-left: 0.8em;
+    padding-top: 0.3em;
+    padding-bottom: 0.3em;
+    font-weight: normal;
+    -webkit-border-radius: 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+}
+
+.signature .literal {
+    font-size: 120%;
+    font-weight: bold;
+    color: #5283a1;
+    padding-left: 0.4em;
+    padding-right: 0.2em;
+}
diff --git a/subprojects/gradle-docs/src/docs/css/style.css b/subprojects/gradle-docs/src/docs/css/style.css
index 85c76e7..c3934f8 100644
--- a/subprojects/gradle-docs/src/docs/css/style.css
+++ b/subprojects/gradle-docs/src/docs/css/style.css
@@ -48,3 +48,11 @@ h3 {
     font-size: 130%;
     margin-top: 1.4em;
 }
+
+h1 a, h2 a, h3 a, h4 a, h5 a {
+    color: inherit;
+}
+
+h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited {
+    color: inherit;
+}
diff --git a/subprojects/gradle-docs/src/docs/dsl/dsl.xml b/subprojects/gradle-docs/src/docs/dsl/dsl.xml
new file mode 100644
index 0000000..215a908
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/dsl.xml
@@ -0,0 +1,249 @@
+<book id="dsl">
+    <bookinfo>
+        <title>Gradle Build Language Reference</title>
+        <titleabbrev>Gradle DSL</titleabbrev>
+    </bookinfo>
+
+    <section>
+        <title>Introduction</title>
+        <para>This reference guide describes the various types which make up the Gradle build language, or DSL.</para>
+    </section>
+
+    <section>
+        <title>Some basics</title>
+        <para>There are a few basic concepts that you should understand, which will help you write Gradle scripts.</para>
+
+        <para>First, Gradle scripts are <firstterm>configuration scripts</firstterm>. As the script executes, it
+            configures an object of a particular type. For example, as a build script executes, it configures an
+            object of type <apilink class="org.gradle.api.Project"/>. This object is called the <firstterm>delegate object</firstterm>
+            of the script. The following table shows the delegate for each type of Gradle script.
+        </para>
+
+        <table>
+            <title>Script delegates</title>
+            <thead>
+                <tr>
+                    <td>Type of script</td>
+                    <td>Delegates to instance of</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>Build script</td>
+                <td>
+                    <apilink class="org.gradle.api.Project"/>
+                </td>
+            </tr>
+            <tr>
+                <td>Init script</td>
+                <td>
+                    <apilink class="org.gradle.api.invocation.Gradle"/>
+                </td>
+            </tr>
+            <tr>
+                <td>Settings script</td>
+                <td>
+                    <apilink class="org.gradle.api.initialization.Settings"/>
+                </td>
+            </tr>
+        </table>
+
+        <para>The properties and methods of the delegate object are available for you to use in the script.</para>
+
+        <para>Second, each Gradle script implements the <apilink class="org.gradle.api.Script"/> interface. This
+            interface defines a number of properties and methods which you can use in the script.
+        </para>
+    </section>
+
+    <!--
+      -
+      - To add more types to this guide, add them to one of the following tables. The contents of
+      - ${classname}.xml for each type listed below is then included in the guide.
+      -
+      -->
+
+    <section>
+        <title>Build script structure</title>
+        <para>A build script is made up of zero or more statements and script blocks. Statements can include method calls,
+            property assignments, and local variable definitions. A script block is a method call which takes a closure
+            as a parameter. The closure is treated as a <firstterm>configuration closure</firstterm> which configures
+            some delegate object as it executes. The top level script blocks are listed below.</para>
+        <table>
+            <title>Build script blocks</title>
+            <tr>
+                <td>allprojects</td>
+            </tr>
+            <tr>
+                <td>artifacts</td>
+            </tr>
+            <tr>
+                <td>buildscript</td>
+            </tr>
+            <tr>
+                <td>configurations</td>
+            </tr>
+            <tr>
+                <td>dependencies</td>
+            </tr>
+            <tr>
+                <td>repositories</td>
+            </tr>
+            <tr>
+                <td>sourceSets</td>
+            </tr>
+            <tr>
+                <td>subprojects</td>
+            </tr>
+        </table>
+        <para>A build script is also a Groovy script, and so can contain those elements allowed in a Groovy script,
+            such as method definitions and class definitions.
+        </para>
+    </section>
+
+    <section>
+        <title>Core types</title>
+        <para>Listed below are some of the central types which are used in Gradle scripts:</para>
+        <table>
+            <title>Core types</title>
+            <tr>
+                <td>org.gradle.api.Project</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.Task</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.invocation.Gradle</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.initialization.Settings</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.Script</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.SourceSet</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.artifacts.Configuration</td>
+            </tr>
+        </table>
+    </section>
+
+    <section>
+        <title>Task types</title>
+        <para>Listed below are the various task types which are available for use in your build script:</para>
+        <table>
+            <title>Task types</title>
+            <tr>
+                <td>org.gradle.api.plugins.antlr.AntlrTask</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.plugins.quality.Checkstyle</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.plugins.quality.CodeNarc</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.compile.Compile</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Copy</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Delete</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Directory</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.diagnostics.DependencyReportTask</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.eclipse.EclipseClasspath</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.eclipse.EclipseJdt</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.eclipse.EclipseProject</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.eclipse.EclipseWtp</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Exec</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.GradleBuild</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.compile.GroovyCompile</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.javadoc.Groovydoc</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.idea.IdeaModule</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.idea.IdeaProject</td>
+            </tr>
+            <tr>
+                <td>org.gradle.plugins.idea.IdeaWorkspace</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.bundling.Jar</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.javadoc.Javadoc</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.JavaExec</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.plugins.jetty.JettyRun</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.plugins.jetty.JettyRunWar</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.plugins.jetty.JettyStop</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.diagnostics.PropertyReportTask</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.diagnostics.ProjectReportTask</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.scala.ScalaCompile</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.scala.ScalaDoc</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Sync</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.bundling.Tar</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.diagnostics.TaskReportTask</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.testing.Test</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.Upload</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.bundling.War</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.wrapper.Wrapper</td>
+            </tr>
+            <tr>
+                <td>org.gradle.api.tasks.bundling.Zip</td>
+            </tr>
+        </table>
+    </section>
+</book>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.DefaultTask.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.DefaultTask.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.DefaultTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Project.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Project.xml
new file mode 100644
index 0000000..a09fc33
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Project.xml
@@ -0,0 +1,235 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>allprojects</td>
+            </tr>
+            <tr>
+                <td>artifacts</td>
+            </tr>
+            <tr>
+                <td>ant</td>
+            </tr>
+            <tr>
+                <td>buildDir</td>
+            </tr>
+            <tr>
+                <td>buildFile</td>
+            </tr>
+            <tr>
+                <td>buildscript</td>
+            </tr>
+            <tr>
+                <td>childProjects</td>
+            </tr>
+            <tr>
+                <td>configurations</td>
+            </tr>
+            <tr>
+                <td>convention</td>
+            </tr>
+            <tr>
+                <td>dependencies</td>
+            </tr>
+            <tr>
+                <td>dependsOnProjects</td>
+            </tr>
+            <tr>
+                <td>defaultTasks</td>
+            </tr>
+            <tr>
+                <td>description</td>
+            </tr>
+            <tr>
+                <td>gradle</td>
+            </tr>
+            <tr>
+                <td>group</td>
+            </tr>
+            <tr>
+                <td>logger</td>
+            </tr>
+            <tr>
+                <td>logging</td>
+            </tr>
+            <tr>
+                <td>name</td>
+            </tr>
+            <tr>
+                <td>parent</td>
+            </tr>
+            <tr>
+                <td>path</td>
+            </tr>
+            <tr>
+                <td>plugins</td>
+            </tr>
+            <tr>
+                <td>project</td>
+            </tr>
+            <tr>
+                <td>projectDir</td>
+            </tr>
+            <tr>
+                <td>properties</td>
+            </tr>
+            <tr>
+                <td>repositories</td>
+            </tr>
+            <tr>
+                <td>rootDir</td>
+            </tr>
+            <tr>
+                <td>rootProject</td>
+            </tr>
+            <tr>
+                <td>state</td>
+            </tr>
+            <tr>
+                <td>status</td>
+            </tr>
+            <tr>
+                <td>subprojects</td>
+            </tr>
+            <tr>
+                <td>tasks</td>
+            </tr>
+            <tr>
+                <td>version</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>ant</td>
+            </tr>
+            <tr>
+                <td>repositories</td>
+            </tr>
+            <tr>
+                <td>configurations</td>
+            </tr>
+            <tr>
+                <td>dependencies</td>
+            </tr>
+            <tr>
+                <td>artifacts</td>
+            </tr>
+            <tr>
+                <td>allprojects</td>
+            </tr>
+            <tr>
+                <td>subprojects</td>
+            </tr>
+            <tr>
+                <td>configure</td>
+            </tr>
+            <tr>
+                <td>buildscript</td>
+            </tr>
+            <tr>
+                <td>apply</td>
+            </tr>
+            <tr>
+                <td>file</td>
+            </tr>
+            <tr>
+                <td>files</td>
+            </tr>
+            <tr>
+                <td>fileTree</td>
+            </tr>
+            <tr>
+                <td>zipTree</td>
+            </tr>
+            <tr>
+                <td>tarTree</td>
+            </tr>
+            <tr>
+                <td>uri</td>
+            </tr>
+            <tr>
+                <td>relativePath</td>
+            </tr>
+            <tr>
+                <td>mkdir</td>
+            </tr>
+            <tr>
+                <td>delete</td>
+            </tr>
+            <tr>
+                <td>copy</td>
+            </tr>
+            <tr>
+                <td>copySpec</td>
+            </tr>
+            <tr>
+                <td>javaexec</td>
+            </tr>
+            <tr>
+                <td>exec</td>
+            </tr>
+            <tr>
+                <td>setProperty</td>
+            </tr>
+            <tr>
+                <td>property</td>
+            </tr>
+            <tr>
+                <td>hasProperty</td>
+            </tr>
+            <tr>
+                <td>task</td>
+            </tr>
+            <tr>
+                <td>dependsOn</td>
+            </tr>
+            <tr>
+                <td>evaluationDependsOn</td>
+            </tr>
+            <tr>
+                <td>childrenDependOnMe</td>
+            </tr>
+            <tr>
+                <td>dependsOnChildren</td>
+            </tr>
+            <tr>
+                <td>findProject</td>
+            </tr>
+            <tr>
+                <td>project</td>
+            </tr>
+            <tr>
+                <td>absoluteProjectPath</td>
+            </tr>
+            <tr>
+                <td>relativeProjectPath</td>
+            </tr>
+            <tr>
+                <td>getAllTasks</td>
+            </tr>
+            <tr>
+                <td>getTasksByName</td>
+            </tr>
+            <tr>
+                <td>beforeEvaluate</td>
+            </tr>
+            <tr>
+                <td>afterEvaluate</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Script.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Script.xml
new file mode 100644
index 0000000..c98eaeb
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Script.xml
@@ -0,0 +1,76 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>buildscript</td>
+            </tr>
+            <tr>
+                <td>logger</td>
+            </tr>
+            <tr>
+                <td>logging</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>apply</td>
+            </tr>
+            <tr>
+                <td>buildscript</td>
+            </tr>
+            <tr>
+                <td>file</td>
+            </tr>
+            <tr>
+                <td>files</td>
+            </tr>
+            <tr>
+                <td>uri</td>
+            </tr>
+            <tr>
+                <td>relativePath</td>
+            </tr>
+            <tr>
+                <td>fileTree</td>
+            </tr>
+            <tr>
+                <td>zipTree</td>
+            </tr>
+            <tr>
+                <td>tarTree</td>
+            </tr>
+            <tr>
+                <td>copy</td>
+            </tr>
+            <tr>
+                <td>copySpec</td>
+            </tr>
+            <tr>
+                <td>mkdir</td>
+            </tr>
+            <tr>
+                <td>delete</td>
+            </tr>
+            <tr>
+                <td>javaexec</td>
+            </tr>
+            <tr>
+                <td>exec</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Task.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Task.xml
new file mode 100644
index 0000000..82369a8
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.Task.xml
@@ -0,0 +1,103 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>name</td>
+            </tr>
+            <tr>
+                <td>project</td>
+            </tr>
+            <tr>
+                <td>path</td>
+            </tr>
+            <tr>
+                <td>actions</td>
+            </tr>
+            <tr>
+                <td>convention</td>
+            </tr>
+            <tr>
+                <td>description</td>
+            </tr>
+            <tr>
+                <td>group</td>
+            </tr>
+            <tr>
+                <td>inputs</td>
+            </tr>
+            <tr>
+                <td>outputs</td>
+            </tr>
+            <tr>
+                <td>temporaryDir</td>
+            </tr>
+            <tr>
+                <td>taskDependencies</td>
+            </tr>
+            <tr>
+                <td>dependsOn</td>
+            </tr>
+            <tr>
+                <td>state</td>
+            </tr>
+            <tr>
+                <td>didWork</td>
+            </tr>
+            <tr>
+                <td>enabled</td>
+            </tr>
+            <tr>
+                <td>ant</td>
+            </tr>
+            <tr>
+                <td>logger</td>
+            </tr>
+            <tr>
+                <td>logging</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>dependsOn</td>
+            </tr>
+            <tr>
+                <td>onlyIf</td>
+            </tr>
+            <tr>
+                <td>doFirst</td>
+            </tr>
+            <tr>
+                <td>doLast</td>
+            </tr>
+            <tr>
+                <td>leftShift</td>
+            </tr>
+            <tr>
+                <td>deleteAllActions</td>
+            </tr>
+            <tr>
+                <td>property</td>
+            </tr>
+            <tr>
+                <td>hasProperty</td>
+            </tr>
+            <tr>
+                <td>setProperty</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.artifacts.Configuration.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.artifacts.Configuration.xml
new file mode 100644
index 0000000..05f6222
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.artifacts.Configuration.xml
@@ -0,0 +1,106 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>name</td>
+            </tr>
+            <tr>
+                <td>description</td>
+            </tr>
+            <tr>
+                <td>state</td>
+            </tr>
+            <tr>
+                <td>visible</td>
+            </tr>
+            <tr>
+                <td>transitive</td>
+            </tr>
+            <tr>
+                <td>extendsFrom</td>
+            </tr>
+            <tr>
+                <td>hierarchy</td>
+            </tr>
+            <tr>
+                <td>resolvedConfiguration</td>
+            </tr>
+            <tr>
+                <td>buildDependencies</td>
+            </tr>
+            <tr>
+                <td>buildArtifacts</td>
+            </tr>
+            <tr>
+                <td>dependencies</td>
+            </tr>
+            <tr>
+                <td>allDependencies</td>
+            </tr>
+            <tr>
+                <td>artifacts</td>
+            </tr>
+            <tr>
+                <td>allArtifacts</td>
+            </tr>
+            <tr>
+                <td>allArtifactFiles</td>
+            </tr>
+            <tr>
+                <td>excludeRules</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>extendsFrom</td>
+            </tr>
+            <tr>
+                <td>files</td>
+            </tr>
+            <tr>
+                <td>fileCollection</td>
+            </tr>
+            <tr>
+                <td>publish</td>
+            </tr>
+            <tr>
+                <td>getDependencies</td>
+            </tr>
+            <tr>
+                <td>getAllDependencies</td>
+            </tr>
+            <tr>
+                <td>addDependency</td>
+            </tr>
+            <tr>
+                <td>addArtifact</td>
+            </tr>
+            <tr>
+                <td>removeArtifact</td>
+            </tr>
+            <tr>
+                <td>exclude</td>
+            </tr>
+            <tr>
+                <td>copy</td>
+            </tr>
+            <tr>
+                <td>copyRecursive</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.initialization.Settings.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.initialization.Settings.xml
new file mode 100644
index 0000000..7a32c23
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.initialization.Settings.xml
@@ -0,0 +1,52 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>gradle</td>
+            </tr>
+            <tr>
+                <td>rootDir</td>
+            </tr>
+            <tr>
+                <td>rootProject</td>
+            </tr>
+            <tr>
+                <td>settings</td>
+            </tr>
+            <tr>
+                <td>settingsDir</td>
+            </tr>
+            <tr>
+                <td>startParameter</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>include</td>
+            </tr>
+            <tr>
+                <td>includeFlat</td>
+            </tr>
+            <tr>
+                <td>findProject</td>
+            </tr>
+            <tr>
+                <td>project</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.AbstractTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.AbstractTask.xml
similarity index 72%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.AbstractTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.AbstractTask.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.AbstractTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.AbstractTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.ConventionTask.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.ConventionTask.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.internal.ConventionTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.invocation.Gradle.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.invocation.Gradle.xml
new file mode 100644
index 0000000..78776cd
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.invocation.Gradle.xml
@@ -0,0 +1,76 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>gradleVersion</td>
+            </tr>
+            <tr>
+                <td>gradleUserHomeDir</td>
+            </tr>
+            <tr>
+                <td>gradle</td>
+            </tr>
+            <tr>
+                <td>parent</td>
+            </tr>
+            <tr>
+                <td>rootProject</td>
+            </tr>
+            <tr>
+                <td>taskGraph</td>
+            </tr>
+            <tr>
+                <td>startParameter</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>addProjectEvaluationListener</td>
+            </tr>
+            <tr>
+                <td>removeProjectEvaluationListener</td>
+            </tr>
+            <tr>
+                <td>beforeProject</td>
+            </tr>
+            <tr>
+                <td>afterProject</td>
+            </tr>
+            <tr>
+                <td>settingsEvaluated</td>
+            </tr>
+            <tr>
+                <td>projectsEvaluated</td>
+            </tr>
+            <tr>
+                <td>buildFinished</td>
+            </tr>
+            <tr>
+                <td>addBuildListener</td>
+            </tr>
+            <tr>
+                <td>addListener</td>
+            </tr>
+            <tr>
+                <td>removeListener</td>
+            </tr>
+            <tr>
+                <td>useLogger</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.BasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.BasePluginConvention.xml
new file mode 100644
index 0000000..350416f
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.BasePluginConvention.xml
@@ -0,0 +1,43 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>distsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.distsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>distsDirName</td>
+                <td><literal>'distributions'</literal></td>
+            </tr>
+            <tr>
+                <td>libsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.libsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>libsDirName</td>
+                <td><literal>'libs'</literal></td>
+            </tr>
+            <tr>
+                <td>archivesBaseName</td>
+                <td><literal>project.name</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.JavaPluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.JavaPluginConvention.xml
new file mode 100644
index 0000000..5a3a489
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.JavaPluginConvention.xml
@@ -0,0 +1,65 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>docsDirName</td>
+                <td><literal>'docs'</literal></td>
+            </tr>
+            <tr>
+                <td>docsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.docsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>testResultsDirName</td>
+                <td><literal>'test-results'</literal></td>
+            </tr>
+            <tr>
+                <td>testResultsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.testResultsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>testReportDirName</td>
+                <td><literal>'tests'</literal></td>
+            </tr>
+            <tr>
+                <td>testReportDir</td>
+                <td><literal><replaceable>${project.reportsDir}</replaceable>/<replaceable>${project.testReportDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>sourceSets</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>sourceCompatibility</td>
+                <td><literal>JavaVersion.JAVA_1_5</literal></td>
+            </tr>
+            <tr>
+                <td>targetCompatibility</td>
+                <td><literal>project.sourceCompatibility</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>sourceSets</td>
+            </tr>
+            <tr>
+                <td>manifest</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.MavenPluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.MavenPluginConvention.xml
new file mode 100644
index 0000000..9924332
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.MavenPluginConvention.xml
@@ -0,0 +1,38 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>maven</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>pomDirName</td>
+                <td><literal>poms</literal></td>
+            </tr>
+            <tr>
+                <td>pomDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.pomDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>conf2ScopeMappings</td>
+                <td/>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>pom</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ProjectReportsPluginConvention.xml
similarity index 52%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ProjectReportsPluginConvention.xml
index e613b39..66e009c 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ProjectReportsPluginConvention.xml
@@ -5,13 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>project-report</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>projectReportDirName</td>
+                <td><literal>'project'</literal></td>
+            </tr>
+            <tr>
+                <td>projectReportDir</td>
+                <td><literal><replaceable>${project.reportsDir}</replaceable>/<replaceable>${project.projectReportDirName}</replaceable></literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +24,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
new file mode 100644
index 0000000..91fb8db
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
@@ -0,0 +1,35 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>reportsDirName</td>
+                <td><literal>'reports'</literal></td>
+            </tr>
+            <tr>
+                <td>reportsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.reportsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>apiDocTitle</td>
+                <td><literal><replaceable>${project.name}</replaceable> <replaceable>{project.version}</replaceable> API</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.WarPluginConvention.xml
similarity index 54%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.WarPluginConvention.xml
index dc9d1ee..91c8c06 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.WarPluginConvention.xml
@@ -5,10 +5,17 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>war</literal> plugin</td>
                 </tr>
             </thead>
+            <tr>
+                <td>webAppDirName</td>
+                <td><literal>'src/main/webapp'</literal></td>
+            </tr>
+            <tr>
+                <td>webAppDir</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.webAppDirName}</replaceable></literal></td>
+            </tr>
         </table>
     </section>
     <section>
@@ -17,15 +24,8 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
-            <tr>
-                <td><literal>withXml</literal></td>
-                <td><literal>IdeaProject withXml(Closure closure)</literal></td>
-                <td>Adds a closure to be called when the ipr xml has been created.</td>
-            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.announce.AnnouncePluginConvention.xml
similarity index 56%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.announce.AnnouncePluginConvention.xml
index e613b39..64490bd 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.announce.AnnouncePluginConvention.xml
@@ -5,13 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>announce</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>username</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>password</td>
+                <td><literal>null</literal></td>
             </tr>
         </table>
     </section>
@@ -21,10 +24,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>announce</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrSourceVirtualDirectory.xml
similarity index 50%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrSourceVirtualDirectory.xml
index e613b39..87988f7 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrSourceVirtualDirectory.xml
@@ -5,13 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>antlr</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>antlr</td>
+                <td><literal>[<replaceable>${project.projectDir}</replaceable>/src/<replaceable>${sourceSet.name}</replaceable>/antlr]</literal></td>
+            </tr>
+            <tr>
+                <td>allAntlr</td>
+                <td><literal>[antlr]</literal></td>
             </tr>
         </table>
     </section>
@@ -21,10 +24,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>antlr</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrTask.xml
new file mode 100644
index 0000000..f64e416
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.antlr.AntlrTask.xml
@@ -0,0 +1,31 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>antlr</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr><td>antlrClasspath</td><td><literal>project.configurations.antlr</literal></td></tr>
+            <tr><td>outputDirectory</td><td>
+                <filename><replaceable>${project.buildDir}</replaceable>/generated-src/antlr/<replaceable>${sourceSet.name}</replaceable></filename></td></tr>
+            <tr><td>trace</td><td><literal>false</literal></td></tr>
+            <tr><td>traceLexer</td><td><literal>false</literal></td></tr>
+            <tr><td>traceParser</td><td><literal>false</literal></td></tr>
+            <tr><td>traceTreeWalker</td><td><literal>false</literal></td></tr>
+            <tr><td>source</td><td><literal><replaceable>sourceSet</replaceable>.antlr</literal></td></tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.AbstractJettyRunTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.AbstractJettyRunTask.xml
new file mode 100644
index 0000000..91bf7f4
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.AbstractJettyRunTask.xml
@@ -0,0 +1,51 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with the <literal>jetty</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>contextPath</td>
+                <td><literal>project.war.baseName</literal></td>
+            </tr>
+            <tr>
+                <td>jettyConfig</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>stopPort</td>
+                <td><literal>project.stopPort</literal></td>
+            </tr>
+            <tr>
+                <td>stopKey</td>
+                <td><literal>project.stopKey</literal></td>
+            </tr>
+            <tr>
+                <td>daemon</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>httpPort</td>
+                <td><literal>project.httpPort</literal></td>
+            </tr>
+            <tr>
+                <td>additionalRuntimeJars</td>
+                <td><literal>[]</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyPluginConvention.xml
similarity index 53%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyPluginConvention.xml
index e613b39..ce462c2 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyPluginConvention.xml
@@ -5,13 +5,20 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>jetty</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>httpPort</td>
+                <td><literal>8080</literal></td>
+            </tr>
+            <tr>
+                <td>stopPort</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>stopKey</td>
+                <td><literal>null</literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +28,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRun.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRun.xml
new file mode 100644
index 0000000..e3e4627
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRun.xml
@@ -0,0 +1,35 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>jetty</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>webXml</td>
+                <td><literal>project.war.webXml</literal>, if not null, or <literal><replaceable>${project.webAppDir}</replaceable>/WEB-INF/web.xml</literal></td>
+            </tr>
+            <tr>
+                <td>webAppSourceDirectory</td>
+                <td><literal>project.webAppDir</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>project.sourceSets.main.runtimeClasspath</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRunWar.xml
similarity index 66%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRunWar.xml
index 4097d29..2f70fd1 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyRunWar.xml
@@ -5,10 +5,13 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>jetty</literal> plugin</td>
                 </tr>
             </thead>
+            <tr>
+                <td>webApp</td>
+                <td><literal>project.war.archivePath</literal></td>
+            </tr>
         </table>
     </section>
     <section>
@@ -17,8 +20,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyStop.xml
similarity index 60%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyStop.xml
index e613b39..9c0613a 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.jetty.JettyStop.xml
@@ -5,13 +5,17 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>jetty</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>stopPort</td>
+                <td><literal>project.stopPort</literal></td>
+            </tr>
+            <tr>
+                <td>stopKey</td>
+
+                <td><literal>project.stopKey</literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +25,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.osgi.OsgiPluginConvention.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.osgi.OsgiPluginConvention.xml
index 4097d29..563c97c 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.osgi.OsgiPluginConvention.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,10 +15,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>osgiManifest</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.Checkstyle.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.Checkstyle.xml
new file mode 100644
index 0000000..3a88251
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.Checkstyle.xml
@@ -0,0 +1,33 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>code-quality</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr><td>classpath</td><td><literal><replaceable>sourceSet</replaceable>.compileClasspath</literal></td></tr>
+            <tr><td>configFile</td><td><literal>project.checkstyleConfigFile</literal></td></tr>
+            <tr><td>ignoreFailures</td><td><literal>false</literal></td></tr>
+            <tr><td>properties</td><td><literal>project.checkstyleProperties</literal></td></tr>
+            <tr>
+                <td>resultFile</td>
+                <td>
+                    <filename><replaceable>${project.checkstyleResultsDir}</replaceable>/<replaceable>${sourceSet.name}</replaceable>.xml</filename>
+                </td></tr>
+            <tr><td>source</td><td><literal><replaceable>sourceSet</replaceable>.allJava</literal></td></tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.CodeNarc.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.CodeNarc.xml
new file mode 100644
index 0000000..df58a0d
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.CodeNarc.xml
@@ -0,0 +1,29 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>code-quality</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr><td>configFile</td><td><literal>project.codeNarcConfigFile</literal></td></tr>
+            <tr><td>reportFile</td><td>
+                <filename><replaceable>${project.codeNarcReportsDir}</replaceable>/<replaceable>${sourceSet.name}</replaceable>.html</filename>
+            </td></tr>
+            <tr><td>ignoreFailures</td><td><literal>false</literal></td></tr>
+            <tr><td>source</td><td><literal><replaceable>sourceSet</replaceable>.allGroovy</literal></td></tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention.xml
new file mode 100644
index 0000000..0a1a78c
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention.xml
@@ -0,0 +1,39 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>code-quality</literal> and <literal>groovy</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>codeNarcConfigFileName</td>
+                <td><literal>'config/codenarc/codenarc.xml'</literal></td>
+            </tr>
+            <tr>
+                <td>codeNarcConfigFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.codeNarcConfigFileName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>codeNarcReportsDirName</td>
+                <td><literal>'codenarc'</literal></td>
+            </tr>
+            <tr>
+                <td>codeNarcReportsDir</td>
+                <td><literal><replaceable>${project.reportsDir}</replaceable>/<replaceable>${project.codeNarcReportsDirName}</replaceable></literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention.xml
new file mode 100644
index 0000000..65c9658
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention.xml
@@ -0,0 +1,43 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>code-quality</literal> and <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>checkstyleConfigFileName</td>
+                <td><literal>'config/checkstyle/checkstyle.xml'</literal></td>
+            </tr>
+            <tr>
+                <td>checkstyleConfigFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.checkstyleConfigFileName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>checkstyleResultsDirName</td>
+                <td><literal>checkstyle</literal></td>
+            </tr>
+            <tr>
+                <td>checkstyleResultsDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/<replaceable>${project.checkstyleResultsDirName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>checkstyleProperties</td>
+                <td><literal>[:]</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.AbstractCopyTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.AbstractCopyTask.xml
new file mode 100644
index 0000000..91d6886
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.AbstractCopyTask.xml
@@ -0,0 +1,74 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>includes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>caseSensitive</td>
+                <td><literal>true</literal></td>
+            </tr>
+            <tr>
+                <td>dirMode</td>
+                <td><literal>0755</literal></td>
+            </tr>
+            <tr>
+                <td>fileMode</td>
+                <td><literal>0644</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>from</td>
+            </tr>
+            <tr>
+                <td>into</td>
+            </tr>
+            <tr>
+                <td>with</td>
+            </tr>
+            <tr>
+                <td>include</td>
+            </tr>
+            <tr>
+                <td>exclude</td>
+            </tr>
+            <tr>
+                <td>rename</td>
+            </tr>
+            <tr>
+                <td>filter</td>
+            </tr>
+            <tr>
+                <td>expand</td>
+            </tr>
+            <tr>
+                <td>eachFile</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Copy.xml
similarity index 71%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Copy.xml
index 4097d29..d01de1a 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Copy.xml
@@ -5,10 +5,13 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default</td>
                 </tr>
             </thead>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal>null</literal></td>
+            </tr>
         </table>
     </section>
     <section>
@@ -17,8 +20,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Delete.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Delete.xml
index 4097d29..eb02209 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Delete.xml
@@ -5,10 +5,10 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr><td>delete</td></tr>
+            <tr><td>targetFiles</td></tr>
         </table>
     </section>
     <section>
@@ -17,10 +17,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>delete</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Directory.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Directory.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Directory.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Exec.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Exec.xml
new file mode 100644
index 0000000..8330f20
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Exec.xml
@@ -0,0 +1,67 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>args</td>
+            </tr>
+            <tr>
+                <td>commandLine</td>
+            </tr>
+            <tr>
+                <td>executable</td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+            </tr>
+            <tr>
+                <td>environment</td>
+            </tr>
+            <tr>
+                <td>standardInput</td>
+            </tr>
+            <tr>
+                <td>standardOutput</td>
+            </tr>
+            <tr>
+                <td>errorOutput</td>
+            </tr>
+            <tr>
+                <td>ignoreExitValue</td>
+            </tr>
+            <tr>
+                <td>execResult</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>commandLine</td>
+            </tr>
+            <tr>
+                <td>args</td>
+            </tr>
+            <tr>
+                <td>executable</td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+            </tr>
+            <tr>
+                <td>environment</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.BasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GeneratorTask.xml
similarity index 62%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.BasePluginConvention.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GeneratorTask.xml
index 133efcd..1d83c14 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.BasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GeneratorTask.xml
@@ -5,13 +5,13 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
             <tr>
-                <td>distsDir</td>
-                <td>The directory which distributions should be generated into.</td>
+                <td>inputFile</td>
+            </tr>
+            <tr>
+                <td>outputFile</td>
             </tr>
         </table>
     </section>
@@ -21,10 +21,14 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>beforeConfigured</td>
+            </tr>
+            <tr>
+                <td>whenConfigured</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GradleBuild.xml
similarity index 65%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GradleBuild.xml
index 0612893..6d6eb82 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GradleBuild.xml
@@ -5,13 +5,19 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
             <tr>
-                <td>outputFile</td>
-                <td>The output file.</td>
+                <td>dir</td>
+            </tr>
+            <tr>
+                <td>buildFile</td>
+            </tr>
+            <tr>
+                <td>tasks</td>
+            </tr>
+            <tr>
+                <td>startParameter</td>
             </tr>
         </table>
     </section>
@@ -21,8 +27,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GroovySourceSet.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GroovySourceSet.xml
similarity index 54%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GroovySourceSet.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GroovySourceSet.xml
index 9dce1a6..8f52c69 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GroovySourceSet.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.GroovySourceSet.xml
@@ -5,15 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>groovy</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
                 <td>groovy</td>
-                <td>The source to be compiled by the Groovy compiler for this source set. Any Java source present in
-                    this set will be passed to the Groovy compiler for joint compilation.
-                </td>
+                <td><literal>[<replaceable>${project.projectDir}</replaceable>/src/<replaceable>${sourceSet.name}</replaceable>/groovy]</literal></td>
+            </tr>
+            <tr>
+                <td>allGroovy</td>
+                <td><literal>[groovy]</literal></td>
             </tr>
         </table>
     </section>
@@ -23,10 +24,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>groovy</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.JavaExec.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.JavaExec.xml
new file mode 100644
index 0000000..bdb079a
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.JavaExec.xml
@@ -0,0 +1,122 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>allJvmArgs</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>jvmArgs</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>systemProperties</td>
+                <td><literal>[:]</literal></td>
+            </tr>
+            <tr>
+                <td>bootstrapClasspath</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>maxHeapSize</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>enableAssertions</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>debug</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>main</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>args</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>executable</td>
+                <td><filename>java</filename> executable for current JVM</td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+                <td><literal>project.projectDir</literal></td>
+            </tr>
+            <tr>
+                <td>environment</td>
+                <td>Current process' environment</td>
+            </tr>
+            <tr>
+                <td>standardInput</td>
+                <td>An empty <classname>InputStream</classname></td>
+            </tr>
+            <tr>
+                <td>standardOutput</td>
+                <td><literal>System.out</literal></td>
+            </tr>
+            <tr>
+                <td>errorOutput</td>
+                <td><literal>System.err</literal></td>
+            </tr>
+            <tr>
+                <td>ignoreExitValue</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>commandLine</td>
+                <td/>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>jvmArgs</td>
+            </tr>
+            <tr>
+                <td>systemProperties</td>
+            </tr>
+            <tr>
+                <td>bootstrapClasspath</td>
+            </tr>
+            <tr>
+                <td>args</td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+            </tr>
+            <tr>
+                <td>copyTo</td>
+            </tr>
+            <tr>
+                <td>executable</td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+            </tr>
+            <tr>
+                <td>environment</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.ScalaSourceSet.xml
similarity index 50%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.ScalaSourceSet.xml
index e613b39..a8a5597 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.ScalaSourceSet.xml
@@ -5,13 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>scala</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>scala</td>
+                <td><literal>[<replaceable>${project.projectDir}</replaceable>/src/<replaceable>${sourceSet.name}</replaceable>/scala]</literal></td>
+            </tr>
+            <tr>
+                <td>allScala</td>
+                <td><literal>[scala]</literal></td>
             </tr>
         </table>
     </section>
@@ -21,10 +24,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>scala</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceSet.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceSet.xml
new file mode 100644
index 0000000..7b7bb39
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceSet.xml
@@ -0,0 +1,74 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>allJava</td>
+                <td><literal>[java]</literal></td>
+            </tr>
+            <tr>
+                <td>allSource</td>
+                <td><literal>[java, resources]</literal></td>
+            </tr>
+            <tr>
+                <td>name</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>classes</td>
+                <td><literal>[classesDir]</literal></td>
+            </tr>
+            <tr>
+                <td>classesDir</td>
+                <td><literal><replaceable>${project.buildDir}</replaceable>/classes/<replaceable>${sourceSet.name}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>compileClasspath</td>
+                <td><literal>project.configurations.compile</literal> (or <literal>project.configurations.testCompile</literal> for the <literal>test</literal> source set).</td>
+            </tr>
+            <tr>
+                <td>java</td>
+                <td><literal>[<replaceable>${project.projectDir}</replaceable>/src/<replaceable>${sourceSet.name}</replaceable>/java]</literal></td>
+            </tr>
+            <tr>
+                <td>resources</td>
+                <td><literal>[<replaceable>${project.projectDir}</replaceable>/src/<replaceable>${sourceSet.name}</replaceable>/resources]</literal></td>
+            </tr>
+            <tr>
+                <td>runtimeClasspath</td>
+                <td><literal>sourceSet.classes + project.configurations.runtime</literal> (or <literal>sourceSet.classes + project.configurations.testRuntime</literal> for the <literal>test</literal> source set).</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>resources</td>
+            </tr>
+            <tr>
+                <td>java</td>
+            </tr>
+            <tr>
+                <td>compiledBy</td>
+            </tr>
+            <tr>
+                <td>getCompileTaskName</td>
+            </tr>
+            <tr>
+                <td>getTaskName</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceTask.xml
similarity index 61%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceTask.xml
index 0612893..ed4696c 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.SourceTask.xml
@@ -5,14 +5,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
-            <tr>
-                <td>outputFile</td>
-                <td>The output file.</td>
-            </tr>
+            <tr><td>includes</td></tr>
+            <tr><td>source</td></tr>
+            <tr><td>excludes</td></tr>
         </table>
     </section>
     <section>
@@ -21,10 +18,17 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>source</td>
+            </tr>
+            <tr>
+                <td>include</td>
+            </tr>
+            <tr>
+                <td>exclude</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Sync.xml
similarity index 71%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Sync.xml
index 4097d29..d01de1a 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.internal.ConventionTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Sync.xml
@@ -5,10 +5,13 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default</td>
                 </tr>
             </thead>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal>null</literal></td>
+            </tr>
         </table>
     </section>
     <section>
@@ -17,8 +20,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Upload.xml
similarity index 57%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Upload.xml
index e613b39..e4ff59f 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.plugins.ReportingBasePluginConvention.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.Upload.xml
@@ -5,13 +5,19 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
             <tr>
-                <td>reportsDirName</td>
-                <td>The name of the reports directory, relative to the project's build directory.</td>
+                <td>uploadDescriptor</td>
+            </tr>
+            <tr>
+                <td>repositories</td>
+            </tr>
+            <tr>
+                <td>configuration</td>
+            </tr>
+            <tr>
+                <td>artifacts</td>
             </tr>
         </table>
     </section>
@@ -21,10 +27,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>repositories</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml
index 4097d29..fbf89fd 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.XmlGeneratorTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,10 +15,11 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>withXml</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml
new file mode 100644
index 0000000..b6bce4f
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml
@@ -0,0 +1,55 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin <overrides>Default</overrides></td>
+                </tr>
+            </thead>
+            <tr>
+                <td>archiveName</td>
+                <td><literal><replaceable>${baseName}</replaceable>-<replaceable>${appendix}</replaceable>-<replaceable>${version}</replaceable>-<replaceable>${classifier}</replaceable>.<replaceable>${extension}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>archivePath</td>
+                <td><literal><replaceable>${destinationDir}</replaceable>/<replaceable>${archiveName}</replaceable></literal></td>
+            </tr>
+            <tr>
+                <td>appendix</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>baseName</td>
+                <td><literal>project.archivesBaseName</literal></td>
+            </tr>
+            <tr>
+                <td>version</td>
+                <td><literal>project.version</literal></td>
+            </tr>
+            <tr>
+                <td>extension</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>classifier</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal>project.distsDir</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Jar.xml
similarity index 52%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Jar.xml
index df268b7..2c5d058 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Jar.xml
@@ -5,18 +5,20 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>java</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
-                <td>archiveName</td>
-                <td>The archive name. If the name has not been explicitly set, the pattern for the name is:
-                    <literal>[baseName]-[appendix]-[version]-[classifier].[extension]</literal>.</td>
+                <td>manifest</td>
+                <td/>
             </tr>
             <tr>
                 <td>destinationDir</td>
-                <td>The directory where the archive is generated into.</td>
+                <td><literal>project.libsDir</literal></td>
+            </tr>
+            <tr>
+                <td>extension</td>
+                <td><literal>jar</literal></td>
             </tr>
         </table>
     </section>
@@ -26,10 +28,14 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
+            <tr>
+                <td>manifest</td>
+            </tr>
+            <tr>
+                <td>metaInf</td>
+            </tr>
         </table>
     </section>
 </section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Tar.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Tar.xml
similarity index 65%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Tar.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Tar.xml
index 80edd91..643427f 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Tar.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Tar.xml
@@ -1,18 +1,20 @@
 <section>
-    <para>Assembles a TAR archive.</para>
     <section>
         <title>Properties</title>
         <table>
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>java</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
                 <td>compression</td>
-                <td>The compression to use for this archive.</td>
+                <td><literal>Compression.NONE</literal></td>
+            </tr>
+            <tr>
+                <td>extension</td>
+                <td><literal>tar</literal></td>
             </tr>
         </table>
     </section>
@@ -22,8 +24,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.War.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.War.xml
new file mode 100644
index 0000000..32efd98
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.War.xml
@@ -0,0 +1,45 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>war</literal> plugin <overrides>Default with <literal>java</literal> plugin</overrides></td>
+                </tr>
+            </thead>
+            <tr>
+                <td>extension</td>
+                <td><literal>war</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>project.configurations.runtime - project.configurations.providedRuntime</literal></td>
+            </tr>
+            <tr>
+                <td>webXml</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal>[project.webAppDir]</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>webInf</td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Zip.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Zip.xml
similarity index 67%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Zip.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Zip.xml
index 8a9a63b..f0d7221 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.bundling.Zip.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.bundling.Zip.xml
@@ -1,15 +1,17 @@
 <section>
-    <para>Assembles a ZIP archive.</para>
     <section>
         <title>Properties</title>
         <table>
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>java</literal> plugin</td>
                 </tr>
             </thead>
+            <tr>
+                <td>extension</td>
+                <td><literal>zip</literal></td>
+            </tr>
         </table>
     </section>
     <section>
@@ -18,8 +20,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.AbstractCompile.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.AbstractCompile.xml
new file mode 100644
index 0000000..2b7d97d
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.AbstractCompile.xml
@@ -0,0 +1,47 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>classpath</td>
+                <td><literal><replaceable>sourceSet</replaceable>.compileClasspath</literal></td>
+            </tr>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal><replaceable>sourceSet</replaceable>.classesDir</literal></td>
+            </tr>
+            <tr>
+                <td>sourceCompatibility</td>
+                <td><literal>project.sourceCompatibility</literal></td>
+            </tr>
+            <tr>
+                <td>targetCompatibility</td>
+                <td><literal>project.targetCompatibility</literal></td>
+            </tr>
+            <tr>
+                <td>includes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.Compile.xml
similarity index 61%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.Compile.xml
index 0612893..99339ae 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.Compile.xml
@@ -5,13 +5,16 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>java</literal> plugin </td>
                 </tr>
             </thead>
             <tr>
-                <td>outputFile</td>
-                <td>The output file.</td>
+                <td>options</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal><replaceable>sourceSet</replaceable>.java</literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +24,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.GroovyCompile.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.GroovyCompile.xml
new file mode 100644
index 0000000..8fecbb5
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.compile.GroovyCompile.xml
@@ -0,0 +1,39 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>groovy</literal> plugin <overrides>Default with <literal>java</literal> plugin</overrides></td>
+                </tr>
+            </thead>
+            <tr>
+                <td>groovyOptions</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>options</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal><replaceable>sourceSet</replaceable>.groovy</literal></td>
+            </tr>
+            <tr>
+                <td>groovyClasspath</td>
+                <td><literal>project.configuations.groovy</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.AbstractReportTask.xml
similarity index 70%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.AbstractReportTask.xml
index 0612893..f65ef7a 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.AbstractReportTask.xml
@@ -5,13 +5,13 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
             <tr>
                 <td>outputFile</td>
-                <td>The output file.</td>
+            </tr>
+            <tr>
+                <td>projects</td>
             </tr>
         </table>
     </section>
@@ -21,8 +21,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.DependencyReportTask.xml
similarity index 51%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.DependencyReportTask.xml
index 0612893..4ff5b58 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.DependencyReportTask.xml
@@ -5,13 +5,20 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>project-report</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
+                <td>configurations</td>
+                <td><literal>project.configurations.all</literal></td>
+            </tr>
+            <tr>
                 <td>outputFile</td>
-                <td>The output file.</td>
+                <td><filename><replaceable>${project.projectReportDir}</replaceable>/dependencies.txt</filename></td>
+            </tr>
+            <tr>
+                <td>projects</td>
+                <td><literal>[project]</literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +28,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.ProjectReportTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.ProjectReportTask.xml
new file mode 100644
index 0000000..bb55ea8
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.ProjectReportTask.xml
@@ -0,0 +1,18 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr><td>Name</td></tr>
+            </thead>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr><td>Name</td></tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.PropertyReportTask.xml
similarity index 72%
copy from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
copy to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.PropertyReportTask.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.PropertyReportTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.TaskReportTask.xml
similarity index 72%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.TaskReportTask.xml
index 4097d29..f46d04e 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.DefaultTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.diagnostics.TaskReportTask.xml
@@ -5,8 +5,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
@@ -17,8 +15,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Groovydoc.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Groovydoc.xml
new file mode 100644
index 0000000..957c45a
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Groovydoc.xml
@@ -0,0 +1,78 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>groovy</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal><replaceable>${project.docsDir}</replaceable>/groovydoc</literal></td>
+            </tr>
+            <tr>
+                <td>groovyClasspath</td>
+                <td><literal>project.configurations.groovy</literal></td>
+            </tr>
+            <tr>
+                <td>use</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>windowTitle</td>
+                <td><literal>project.apiDocTitle</literal></td>
+            </tr>
+            <tr>
+                <td>docTitle</td>
+                <td><literal>project.apiDocTitle</literal></td>
+            </tr>
+            <tr>
+                <td>header</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>footer</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>overview</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>includePrivate</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>links</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>includes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal>sourceSets.main.groovy</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>link</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml
new file mode 100644
index 0000000..ea84775
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.javadoc.Javadoc.xml
@@ -0,0 +1,63 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal><replaceable>${project.docsDir}</replaceable>/javadoc</literal></td>
+            </tr>
+            <tr>
+                <td>maxMemory</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>title</td>
+                <td><literal>project.apiDocTitle</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>project.sourceSets.main.compileClasspath</literal></td>
+            </tr>
+            <tr>
+                <td>options</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>failOnError</td>
+                <td><literal>true</literal></td>
+            </tr>
+            <tr>
+                <td>executable</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal>project.sourceSets.main.allJava</literal></td>
+            </tr>
+            <tr>
+                <td>includes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaCompile.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaCompile.xml
new file mode 100644
index 0000000..2cb9132
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaCompile.xml
@@ -0,0 +1,35 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>scala</literal> plugin <overrides>Default with <litera>java</litera> plugin</overrides></td>
+                </tr>
+            </thead>
+            <tr>
+                <td>scalaClasspath</td>
+                <td><literal>project.configurations.scalaTools</literal></td>
+            </tr>
+            <tr>
+                <td>scalaCompileOptions</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal><replaceable>sourceSet</replaceable>.scala</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaDoc.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaDoc.xml
new file mode 100644
index 0000000..425963c
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.scala.ScalaDoc.xml
@@ -0,0 +1,55 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>scala</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>destinationDir</td>
+                <td><literal><replaceable>${project.docsDir}</replaceable>/scaladoc</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>project.sourceSets.main.classes + project.sourceSets.main.compileClasspath</literal></td>
+            </tr>
+            <tr>
+                <td>scalaClasspath</td>
+                <td><literal>project.configurations.scalaTools</literal></td>
+            </tr>
+            <tr>
+                <td>scalaDocOptions</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>title</td>
+                <td><literal>project.apiDocTitle</literal></td>
+            </tr>
+            <tr>
+                <td>includes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>source</td>
+                <td><literal>project.sourceSets.main.scala</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.testing.Test.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.testing.Test.xml
new file mode 100644
index 0000000..70e48f4
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.testing.Test.xml
@@ -0,0 +1,160 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>testClassesDir</td>
+                <td><literal>project.sourceSets.test.classesDir</literal></td>
+            </tr>
+            <tr>
+                <td>testResultsDir</td>
+                <td><literal>project.testResultsDir</literal></td>
+            </tr>
+            <tr>
+                <td>testReportDir</td>
+                <td><literal>project.testReportDir</literal></td>
+            </tr>
+            <tr>
+                <td>classpath</td>
+                <td><literal>project.sourceSets.test.runtimeClasspath</literal></td>
+            </tr>
+            <tr>
+                <td>testSrcDirs</td>
+                <td><literal>project.sourceSets.test.java.srcDirs</literal></td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+                <td><literal>project.projectDir</literal></td>
+            </tr>
+            <tr>
+                <td>testReport</td>
+                <td><literal>true</literal></td>
+            </tr>
+            <tr>
+                <td>scanForTestClasses</td>
+                <td><literal>true</literal></td>
+            </tr>
+            <tr>
+                <td>forkEvery</td>
+                <td><literal>0</literal></td>
+            </tr>
+            <tr>
+                <td>maxParallelForks</td>
+                <td><literal>1</literal></td>
+            </tr>
+            <tr>
+                <td>executable</td>
+                <td><command>java</command> command for the current JVM.</td>
+            </tr>
+            <tr>
+                <td>systemProperties</td>
+                <td><literal>[:]</literal></td>
+            </tr>
+            <tr>
+                <td>bootstrapClasspath</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>maxHeapSize</td>
+                <td><literal>null</literal></td>
+            </tr>
+            <tr>
+                <td>jvmArgs</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>enableAssertions</td>
+                <td><literal><literal>true</literal></literal></td>
+            </tr>
+            <tr>
+                <td>debug</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>allJvmArgs</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>environment</td>
+                <td>environment of the current process</td>
+            </tr>
+            <tr>
+                <td>ignoreFailures</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>options</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>includes</td>
+                <td>[]</td>
+            </tr>
+            <tr>
+                <td>excludes</td>
+                <td>[]</td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>addTestListener</td>
+            </tr>
+            <tr>
+                <td>removeTestListener</td>
+            </tr>
+            <tr>
+                <td>beforeSuite</td>
+            </tr>
+            <tr>
+                <td>afterSuite</td>
+            </tr>
+            <tr>
+                <td>beforeTest</td>
+            </tr>
+            <tr>
+                <td>afterTest</td>
+            </tr>
+            <tr>
+                <td>useJUnit</td>
+            </tr>
+            <tr>
+                <td>useTestNG</td>
+            </tr>
+            <tr>
+                <td>workingDir</td>
+            </tr>
+            <tr>
+                <td>executable</td>
+            </tr>
+            <tr>
+                <td>systemProperties</td>
+            </tr>
+            <tr>
+                <td>bootstrapClasspath</td>
+            </tr>
+            <tr>
+                <td>jvmArgs</td>
+            </tr>
+            <tr>
+                <td>environment</td>
+            </tr>
+            <tr>
+                <td>copyTo</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml
new file mode 100644
index 0000000..4071dc2
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml
@@ -0,0 +1,67 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>scriptFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/gradlew</literal></td>
+            </tr>
+            <tr>
+                <td>jarFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/gradle/wrapper/gradle-wrapper.jar</literal></td>
+            </tr>
+            <tr>
+                <td>propertiesFile</td>
+                <td><literal>jarFile</literal>, replacing <literal>.jar</literal> with <literal>.properties</literal></td>
+            </tr>
+            <tr>
+                <td>distributionPath</td>
+                <td><literal>'wrapper/dists'</literal></td>
+            </tr>
+            <tr>
+                <td>distributionBase</td>
+                <td><literal>PathBase.GRADLE_USER_HOME</literal></td>
+            </tr>
+            <tr>
+                <td>archivePath</td>
+                <td><literal>'wrapper/dists'</literal></td>
+            </tr>
+            <tr>
+                <td>archiveBase</td>
+                <td><literal>PathBase.GRADLE_USER_HOME</literal></td>
+            </tr>
+            <tr>
+                <td>archiveName</td>
+                <td><literal>'gradle'</literal></td>
+            </tr>
+            <tr>
+                <td>archiveClassifier</td>
+                <td><literal>'bin'</literal></td>
+            </tr>
+            <tr>
+                <td>urlRoot</td>
+                <td><literal>'http://dist.codehaus.org/gradle'</literal></td>
+            </tr>
+            <tr>
+                <td>gradleVersion</td>
+                <td><literal>gradle.gradleVersion</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseClasspath.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseClasspath.xml
new file mode 100644
index 0000000..38b06a5
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseClasspath.xml
@@ -0,0 +1,65 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>eclipse</literal> and <literal>java</literal> plugins</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>sourceSets</td>
+                <td><literal>project.sourceSets</literal></td>
+            </tr>
+            <tr>
+                <td>plusConfigurations</td>
+                <td><literal>project.configurations.testRuntime</literal></td>
+            </tr>
+            <tr>
+                <td>minusConfigurations</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>variables</td>
+                <td><literal>[:]</literal></td>
+            </tr>
+            <tr>
+                <td>containers</td>
+                <td>[JRE container]</td>
+            </tr>
+            <tr>
+                <td>defaultOutputDir</td>
+                <td><literal>project.sourceSets.main.classesDir</literal></td>
+            </tr>
+            <tr>
+                <td>downloadSources</td>
+                <td><literal>true</literal></td>
+            </tr>
+            <tr>
+                <td>downloadJavadoc</td>
+                <td><literal>false</literal></td>
+            </tr>
+            <tr>
+                <td>outputFile</td>
+                <td><filename><replaceable>${project.projectDir}</replaceable>/.classpath</filename></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>containers</td>
+            </tr>
+            <tr>
+                <td>variables</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.SourceSet.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseJdt.xml
similarity index 50%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.SourceSet.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseJdt.xml
index 695de81..9a13daf 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.SourceSet.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseJdt.xml
@@ -1,26 +1,24 @@
 <section>
-    <para>Represents a logical group of Java source and resources.</para>
     <section>
         <title>Properties</title>
         <table>
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>eclipse</literal> and <literal>java</literal> plugins</td>
                 </tr>
             </thead>
             <tr>
-                <td>name</td>
-                <td>The name of the source set.</td>
+                <td>sourceCompatibility</td>
+                <td><literal>project.sourceCompatibility</literal></td>
             </tr>
             <tr>
-                <td>compileClasspath</td>
-                <td>The classpath used to compile this source.</td>
+                <td>targetCompatibility</td>
+                <td><literal>project.targetCompatibility</literal></td>
             </tr>
             <tr>
-                <td>runtimeClasspath</td>
-                <td>The classpath used to execute this source.</td>
+                <td>outputFile</td>
+                <td><filename><replaceable>${project.projectDir}</replaceable>/.settings/org.eclipse.jdt.core.prefs</filename></td>
             </tr>
         </table>
     </section>
@@ -30,8 +28,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseProject.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseProject.xml
new file mode 100644
index 0000000..34e95fd
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseProject.xml
@@ -0,0 +1,63 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>eclipse</literal> and <literal>java</literal> plugins</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>projectName</td>
+                <td><literal>project.name</literal></td>
+            </tr>
+            <tr>
+                <td>comment</td>
+                <td><literal>project.description</literal></td>
+            </tr>
+            <tr>
+                <td>referencedProjects</td>
+                <td>[]</td>
+            </tr>
+            <tr>
+                <td>natures</td>
+                <td>Java nature, plus Groovy, Scala and Web natures as appropriate.</td>
+            </tr>
+            <tr>
+                <td>buildCommands</td>
+                <td>Java builder, plus Scala and Web builders as appropriate.</td>
+            </tr>
+            <tr>
+                <td>links</td>
+                <td>[]</td>
+            </tr>
+            <tr>
+                <td>outputFile</td>
+                <td><filename><replaceable>${project.projectDir}</replaceable>/.project</filename></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>natures</td>
+            </tr>
+            <tr>
+                <td>referencedProjects</td>
+            </tr>
+            <tr>
+                <td>buildCommand</td>
+            </tr>
+            <tr>
+                <td>link</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseWtp.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseWtp.xml
new file mode 100644
index 0000000..0a47334
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.eclipse.EclipseWtp.xml
@@ -0,0 +1,96 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>eclipse</literal> and <literal>war</literal> plugins</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>orgEclipseWstCommonComponentInputFile</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>orgEclipseWstCommonComponentOutputFile</td>
+                <td><filename><replaceable>${project.projectDir}</replaceable>/.settings/org.eclipse.wst.common.component</filename></td>
+            </tr>
+            <tr>
+                <td>orgEclipseWstCommonProjectFacetCoreInputFile</td>
+                <td/>
+            </tr>
+            <tr>
+                <td>orgEclipseWstCommonProjectFacetCoreOutputFile</td>
+                <td><filename><replaceable>${project.projectDir}</replaceable>/.settings/org.eclipse.wst.common.project.facet.core.xml</filename></td>
+            </tr>
+            <tr>
+                <td>sourceSets</td>
+                <td><literal>[project.sourceSets.main]</literal></td>
+            </tr>
+            <tr>
+                <td>plusConfigurations</td>
+                <td><literal>[project.configurations.runtime]</literal></td>
+            </tr>
+            <tr>
+                <td>minusConfigurations</td>
+                <td><literal>[project.configurations.providedRuntime]</literal></td>
+            </tr>
+            <tr>
+                <td>facets</td>
+                <td>Java and web facets.</td>
+            </tr>
+            <tr>
+                <td>deployName</td>
+                <td><literal>project.name</literal></td>
+            </tr>
+            <tr>
+                <td>variables</td>
+                <td><literal>[:]</literal></td>
+            </tr>
+            <tr>
+                <td>resources</td>
+                <td><literal>[deployPath: '/', sourcePath: project.webAppDirName]</literal></td>
+            </tr>
+            <tr>
+                <td>properties</td>
+                <td><literal>[]</literal></td>
+            </tr>
+            <tr>
+                <td>contextPath</td>
+                <td><literal>project.war.baseName</literal></td>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>facet</td>
+            </tr>
+            <tr>
+                <td>variables</td>
+            </tr>
+            <tr>
+                <td>property</td>
+            </tr>
+            <tr>
+                <td>resource</td>
+            </tr>
+            <tr>
+                <td>withXml</td>
+            </tr>
+            <tr>
+                <td>beforeConfigured</td>
+            </tr>
+            <tr>
+                <td>whenConfigured</td>
+            </tr>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaModule.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaModule.xml
new file mode 100644
index 0000000..82b429d
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaModule.xml
@@ -0,0 +1,90 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>idea</literal> plugin</td>
+                    <td>Default with <literal>idea</literal> and <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>moduleDir</td>
+                <td><literal>project.projectDir</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>sourceDirs</td>
+                <td><literal>[]</literal></td>
+                <td>source dirs from <literal>project.sourceSets.main.allSource</literal></td>
+            </tr>
+            <tr>
+                <td>testSourceDirs</td>
+                <td><literal>[]</literal></td>
+                <td>source dirs from <literal>project.sourceSets.test.allSource</literal></td>
+            </tr>
+            <tr>
+                <td>excludeDirs</td>
+                <td><literal>[project.buildDir, project.file('.gradle')]</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>outputDir</td>
+                <td><literal>null</literal></td>
+                <td><literal>project.sourceSets.main.classesDir</literal></td>
+            </tr>
+            <tr>
+                <td>testOutputDir</td>
+                <td><literal>null</literal></td>
+                <td><literal>project.sourceSets.test.classesDir</literal></td>
+            </tr>
+            <tr>
+                <td>javaVersion</td>
+                <td><literal>'inherited'</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>downloadSources</td>
+                <td><literal>true</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>downloadJavadoc</td>
+                <td><literal>false</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>variables</td>
+                <td><literal>[:]</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>scopes</td>
+                <td><literal>[:]</literal></td>
+                <td>
+                    <itemizedlist>
+                        <listitem><literal>COMPILE</literal> -> <literal>project.configurations.compile</literal></listitem>
+                        <listitem><literal>RUNTIME</literal> -> <literal>project.configurations.runtime - project.configurations.compile</literal></listitem>
+                        <listitem><literal>TEST</literal> -> <literal>project.configurations.testRuntime - project.configurations.runtime</literal></listitem>
+                    </itemizedlist>
+                </td>
+            </tr>
+            <tr>
+                <td>outputFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.name}</replaceable>.iml</literal></td>
+                <td/>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaProject.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaProject.xml
new file mode 100644
index 0000000..9acd2be
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaProject.xml
@@ -0,0 +1,44 @@
+<section>
+    <section>
+        <title>Properties</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                    <td>Default with <literal>idea</literal> plugin</td>
+                    <td>Default with <literal>idea</literal> and <literal>java</literal> plugin</td>
+                </tr>
+            </thead>
+            <tr>
+                <td>javaVersion</td>
+                <td><literal>'1.6'</literal></td>
+                <td><literal>project.sourceCompatibility</literal></td>
+            </tr>
+            <tr>
+                <td>subprojects</td>
+                <td><literal>project.allprojects</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>wildcards</td>
+                <td><literal>['!?*.java', '!?*.groovy']</literal></td>
+                <td/>
+            </tr>
+            <tr>
+                <td>outputFile</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.name}</replaceable>.ipr</literal></td>
+                <td/>
+            </tr>
+        </table>
+    </section>
+    <section>
+        <title>Methods</title>
+        <table>
+            <thead>
+                <tr>
+                    <td>Name</td>
+                </tr>
+            </thead>
+        </table>
+    </section>
+</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaWorkspace.xml
similarity index 69%
rename from subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
rename to subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaWorkspace.xml
index 0612893..cd2e510 100644
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.GeneratorTask.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.plugins.idea.IdeaWorkspace.xml
@@ -5,13 +5,12 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
+                    <td>Default with <literal>idea</literal> plugin</td>
                 </tr>
             </thead>
             <tr>
                 <td>outputFile</td>
-                <td>The output file.</td>
+                <td><literal><replaceable>${project.projectDir}</replaceable>/<replaceable>${project.name}</replaceable>.iws</literal></td>
             </tr>
         </table>
     </section>
@@ -21,8 +20,6 @@
             <thead>
                 <tr>
                     <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
                 </tr>
             </thead>
         </table>
diff --git a/subprojects/gradle-docs/src/docs/dsl/plugins.xml b/subprojects/gradle-docs/src/docs/dsl/plugins.xml
new file mode 100644
index 0000000..5a14276
--- /dev/null
+++ b/subprojects/gradle-docs/src/docs/dsl/plugins.xml
@@ -0,0 +1,38 @@
+<plugins>
+    <plugin id="java" description="Java Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.BasePluginConvention"/>
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.ReportingBasePluginConvention"/>
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.JavaPluginConvention"/>
+    </plugin>
+    <plugin id="groovy" description="Groovy Plugin">
+        <extends targetClass="org.gradle.api.tasks.SourceSet" extensionClass="org.gradle.api.tasks.GroovySourceSet"/>
+    </plugin>
+    <plugin id="scala" description="Scala Plugin">
+        <extends targetClass="org.gradle.api.tasks.SourceSet" extensionClass="org.gradle.api.tasks.ScalaSourceSet"/>
+    </plugin>
+    <plugin id="antlr" description="Antlr Plugin">
+        <extends targetClass="org.gradle.api.tasks.SourceSet" extensionClass="org.gradle.api.plugins.antlr.AntlrSourceVirtualDirectory"/>
+    </plugin>
+    <plugin id="code-quality" description="Code Quality Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention"/>
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention"/>
+    </plugin>
+    <plugin id="maven" description="Maven Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.MavenPluginConvention"/>
+    </plugin>
+    <plugin id="war" description="War Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.WarPluginConvention"/>
+    </plugin>
+    <plugin id="jetty" description="Jetty Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.jetty.JettyPluginConvention"/>
+    </plugin>
+    <plugin id="project-report" description="Project Report Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.ProjectReportsPluginConvention"/>
+    </plugin>
+    <plugin id="announce" description="Announce Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.announce.AnnouncePluginConvention"/>
+    </plugin>
+    <plugin id="osgi" description="OSGi Plugin">
+        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.osgi.OsgiPluginConvention"/>
+    </plugin>
+</plugins>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/stylesheets/dslHtml.xsl b/subprojects/gradle-docs/src/docs/stylesheets/dslHtml.xsl
index f4c3ef1..555afb4 100644
--- a/subprojects/gradle-docs/src/docs/stylesheets/dslHtml.xsl
+++ b/subprojects/gradle-docs/src/docs/stylesheets/dslHtml.xsl
@@ -13,11 +13,13 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<xsl:stylesheet
-        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
     <xsl:import href="html/chunkfast.xsl"/>
     <xsl:import href="userGuideHtmlCommon.xsl"/>
 
+    <xsl:output method="html" doctype-system="http://www.w3.org/TR/html4/strict.dtd"
+         doctype-public="-//W3C//DTD HTML 4.01//EN"/>
+
     <xsl:param name="root.filename">index</xsl:param>
     <xsl:param name="chunk.section.depth">0</xsl:param>
     <xsl:param name="chunk.quietly">1</xsl:param>
@@ -25,10 +27,13 @@
     <xsl:param name="section.autolabel">0</xsl:param>
     <xsl:param name="chapter.autolabel">0</xsl:param>
     <xsl:param name="appendix.autolabel">0</xsl:param>
+    <xsl:param name="table.autolabel">0</xsl:param>
 
     <!-- No table of contents -->
     <xsl:param name="generate.toc"/>
 
+    <xsl:template name="formal.object.heading"></xsl:template>
+
     <!-- customise the stylesheets to add to the <head> element -->
     <xsl:template name="output.html.stylesheets">
         <link href="base.css" rel="stylesheet" type="text/css"/>
@@ -36,6 +41,19 @@
         <link href="dsl.css" rel="stylesheet" type="text/css"/>
     </xsl:template>
 
+    <!-- Customise the page titles -->
+    <xsl:template match="book" mode="object.title.markup.textonly">
+        <xsl:value-of select="bookinfo/titleabbrev"/>
+        <xsl:text> Version </xsl:text>
+        <xsl:value-of select="bookinfo/releaseinfo"/>
+    </xsl:template>
+
+    <xsl:template match="chapter" mode="object.title.markup.textonly">
+        <xsl:value-of select="title"/>
+        <xsl:text> - </xsl:text>
+        <xsl:apply-templates select="/book" mode="object.title.markup.textonly"/>
+    </xsl:template>
+
     <!-- customise the layout of the html page -->
     <xsl:template name="chunk-element-content">
         <xsl:param name="prev"/>
@@ -55,12 +73,14 @@
                 <xsl:call-template name="body.attributes"/>
                 <div class="sidebar">
                     <ul>
-                        <xsl:apply-templates select="/" mode="sidebar"/>
+                        <xsl:apply-templates select="." mode="sidebar"/>
+                        <xsl:apply-templates select="/book/section/table[@role = 'dslTypes']" mode="sidebar"/>
                     </ul>
                 </div>
                 <div class="content">
                     <xsl:copy-of select="$content"/>
                 </div>
+                <!--<script src="sidebar.js" type="text/javascript"/>-->
             </body>
         </html>
         <xsl:value-of select="$chunk.append"/>
@@ -71,15 +91,48 @@
       -->
 
     <xsl:template match="book" mode="sidebar">
+        <li class='sidebarHeading selected'>
+            Home
+        </li>
+        <ul class='sections'>
+            <xsl:apply-templates select="section" mode="sidebar.link"/>
+        </ul>
+    </xsl:template>
+
+    <xsl:template match="chapter" mode="sidebar">
+        <li>
+            <xsl:call-template name="customXref">
+                <xsl:with-param name="target" select="/"/>
+                <xsl:with-param name="content">
+                    <xsl:text>Home</xsl:text>
+                </xsl:with-param>
+            </xsl:call-template>
+        </li>
+        <li class='sidebarHeading selected'>
+            <xsl:value-of select="title"/>
+        </li>
+        <ul class='sections'>
+            <xsl:apply-templates select="section[table]" mode="sidebar.link"/>
+        </ul>
+    </xsl:template>
+
+    <xsl:template match="section" mode="sidebar.link">
         <li>
             <xsl:call-template name="customXref">
                 <xsl:with-param name="target" select="."/>
                 <xsl:with-param name="content">
-                    <xsl:text>Contents</xsl:text>
+                    <xsl:choose>
+                        <xsl:when test="titleabbrev"><xsl:value-of select="titleabbrev"/></xsl:when>
+                        <xsl:otherwise><xsl:value-of select="title"/></xsl:otherwise>
+                    </xsl:choose>
                 </xsl:with-param>
             </xsl:call-template>
         </li>
-        <xsl:apply-templates select="section[1]/table[@role = 'dslTypes']" mode="sidebar"/>
+        <xsl:if test="section[table]">
+            <ul class='sections'>
+                <xsl:apply-templates select="section[table]" mode="sidebar.link"/>
+            </ul>
+        </xsl:if>
     </xsl:template>
 
     <xsl:template match="table" mode="sidebar">
@@ -94,4 +147,66 @@
             <xsl:apply-templates select="link"/>
         </li>
     </xsl:template>
+
+    <!--
+      - Customised header for property and method detail sections
+      -->
+
+    <xsl:template match="section[@role='detail']/title" mode="titlepage.mode">
+        <xsl:variable name="level">
+            <xsl:call-template name="section.level">
+                <xsl:with-param name="node" select="ancestor::section"/>
+            </xsl:call-template>
+        </xsl:variable>
+
+        <xsl:element name="h{$level+1}">
+            <xsl:attribute name="class">signature</xsl:attribute>
+            <xsl:call-template name="anchor">
+                <xsl:with-param name="node" select="ancestor::section"/>
+                <xsl:with-param name="conditional" select="0"/>
+            </xsl:call-template>
+            <xsl:apply-templates/>
+        </xsl:element>
+    </xsl:template>
+
+    <!--
+      - Customised <segmentedlist> formats
+      -->
+    <xsl:template match="segmentedlist">
+        <div>
+            <xsl:call-template name="common.html.attributes"/>
+            <xsl:call-template name="anchor"/>
+            <table>
+                <xsl:apply-templates select="seglistitem/seg" mode="seglist.table"/>
+            </table>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="section[@role='detail']/segmentedlist">
+        <div>
+            <xsl:call-template name="common.html.attributes"/>
+            <xsl:call-template name="anchor"/>
+            <dl>
+                <xsl:apply-templates select="seglistitem/seg" mode="seglist.list"/>
+            </dl>
+        </div>
+    </xsl:template>
+
+    <xsl:template match="seg" mode="seglist.table">
+        <xsl:variable name="segnum" select="count(preceding-sibling::seg)+1"/>
+        <xsl:variable name="seglist" select="ancestor::segmentedlist"/>
+        <xsl:variable name="segtitles" select="$seglist/segtitle"/>
+        <tr>
+            <th><xsl:apply-templates select="$segtitles[$segnum=position()]" mode="segtitle-in-seg"/>:</th>
+            <td><xsl:apply-templates/></td>
+        </tr>
+    </xsl:template>
+
+    <xsl:template match="seg" mode="seglist.list">
+        <xsl:variable name="segnum" select="count(preceding-sibling::seg)+1"/>
+        <xsl:variable name="seglist" select="ancestor::segmentedlist"/>
+        <xsl:variable name="segtitles" select="$seglist/segtitle"/>
+        <dt><xsl:apply-templates select="$segtitles[$segnum=position()]" mode="segtitle-in-seg"/>:</dt>
+        <dd><xsl:apply-templates/></dd>
+    </xsl:template>
 </xsl:stylesheet>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/codeQualityPlugin.xml b/subprojects/gradle-docs/src/docs/userguide/codeQualityPlugin.xml
index d40ddba..9481247 100644
--- a/subprojects/gradle-docs/src/docs/userguide/codeQualityPlugin.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/codeQualityPlugin.xml
@@ -243,7 +243,7 @@
         </table>
 
         <para>These convention properties are provided by a convention object of type
-            <apilink class="org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention" lang="groovy"/>.</para>
+            <apilink class="org.gradle.api.plugins.quality.JavaCodeQualityPluginConvention"/>.</para>
 
         <para>When used with the Groovy plugin, the code quality plugin adds the following convention properties to the project:</para>
 
@@ -316,7 +316,7 @@
         </table>
 
         <para>These convention properties are provided by a convention object of type
-            <apilink class="org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention" lang="groovy"/>.</para>
+            <apilink class="org.gradle.api.plugins.quality.GroovyCodeQualityPluginConvention"/>.</para>
     </section>
 
 </chapter>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/customTasks.xml b/subprojects/gradle-docs/src/docs/userguide/customTasks.xml
index 0d3b045..3b647cb 100644
--- a/subprojects/gradle-docs/src/docs/userguide/customTasks.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/customTasks.xml
@@ -86,7 +86,7 @@
 
     <section>
         <title>Writing a simple task</title>
-        <para>To implement a custom task, you extend <apilink class="org.gradle.api.DefaultTask" lang="groovy"/>.
+        <para>To implement a custom task, you extend <apilink class="org.gradle.api.DefaultTask"/>.
         </para>
         <sample id="customTask" dir="userguide/tasks/customTask" title="Defining a custom task">
             <sourcefile file="build.gradle" snippet="define-task"/>
diff --git a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
index c54e24f..d5b37c7 100644
--- a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
@@ -229,7 +229,7 @@
             <para>This declares a dependency of your project on Groovy. Groovy itself has dependencies. But Gradle does
                 not look for an XML descriptor to figure them out but gets the information from the build file. The
                 dependencies of a client module can be normal module dependencies or artifact dependencies or another
-                client module. Have also a look at the javadoc: <apilink class='org.gradle.api.artifacts.ClientModule'/>
+                client module. Have also a look at the API documentation: <apilink class='org.gradle.api.artifacts.ClientModule'/>
             </para>
             <para>In the current release client modules have one limitation. Let's say your project is a library and
                 you want this library to be uploaded to your company's Maven or Ivy repository. Gradle uploads the
@@ -246,7 +246,7 @@
             <sample id="project-dependencies" dir="java/multiproject/api" title="Project dependencies">
                 <sourcefile file="build.gradle" snippet="project-dependencies"/>
             </sample>
-            <para>For more information see the javadoc for <apilink class="org.gradle.api.artifacts.ProjectDependency"/>
+            <para>For more information see the API documentation for <apilink class="org.gradle.api.artifacts.ProjectDependency"/>
             </para>
             <para>Multi-project builds are discussed in <xref linkend='multi_project_builds'/>.
             </para>
@@ -298,7 +298,7 @@
                 configurations you can use the Groovy spread-dot operator to express this in a concise way, as shown in the example.
                 When defining an exclude, you can
                 specify either only the organization or only the module name or both.
-                Have also a look at the javadoc of <apilink class="org.gradle.api.artifacts.Dependency"/> and
+                Have also a look at the API documentation of <apilink class="org.gradle.api.artifacts.Dependency"/> and
                 <apilink class="org.gradle.api.artifacts.Configuration"/>.
             </para>
         </section>
@@ -404,7 +404,7 @@
             will cause an exception. You can always copy a resolved configuration. The copied configuration is in the unresolved
             state and can be freshly resolved.
         </para>
-        <para>To learn more about the API of the configuration class see the javadoc:
+        <para>To learn more about the API of the configuration class see the API documentation:
             <apilink class='org.gradle.api.artifacts.Configuration'/>.
         </para>
     </section>
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/dsl.xml b/subprojects/gradle-docs/src/docs/userguide/dsl/dsl.xml
deleted file mode 100644
index 934a7b5..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/dsl.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<book id="dsl">
-    <bookinfo>
-        <title>Gradle DSL Reference</title>
-    </bookinfo>
-
-    <section>
-        <title>Introduction</title>
-        <note>
-            <para>This reference guide is under construction.</para>
-        </note>
-        <para>This reference guide describes the various types which make up the Gradle build DSL.</para>
-
-        <!--
-        -
-        - To add more types to this guide, add them to one of the following tables. The contents of
-        - ${classname}.xml for each type listed below is then included in the guide.
-        -
-        -->
-
-        <table>
-            <title>Core types</title>
-            <tr>
-                <td>org.gradle.api.Project</td>
-            </tr>
-            <tr>
-                <td>org.gradle.api.tasks.SourceSet</td>
-            </tr>
-        </table>
-        <table>
-            <title>Task types</title>
-            <tr>
-                <td>org.gradle.plugins.idea.IdeaProject</td>
-            </tr>
-            <tr>
-                <td>org.gradle.api.tasks.bundling.Tar</td>
-            </tr>
-            <tr>
-                <td>org.gradle.api.tasks.bundling.Zip</td>
-            </tr>
-        </table>
-    </section>
-</book>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.Project.xml b/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.Project.xml
deleted file mode 100644
index f8334fb..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.Project.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<section>
-    <para>The main API you use to interact with Gradle from your build file.</para>
-    <section>
-        <title>Properties</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-            <tr>
-                <td>name</td>
-                <td>The name of the project.</td>
-            </tr>
-            <tr>
-                <td>path</td>
-                <td>The path of the project.</td>
-            </tr>
-        </table>
-    </section>
-    <section>
-        <title>Methods</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-            <tr>
-                <td><literal>file</literal></td>
-                <td><literal>File file(Object path)</literal></td>
-                <td>Resolves a file path relative to the project directory of this project.</td>
-            </tr>
-        </table>
-    </section>
-</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.AbstractCopyTask.xml b/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.AbstractCopyTask.xml
deleted file mode 100644
index 23d7304..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.api.tasks.AbstractCopyTask.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<section>
-    <section>
-        <title>Properties</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-            <tr>
-                <td>includes</td>
-                <td>The set of include patterns.</td>
-            </tr>
-            <tr>
-                <td>excludes</td>
-                <td>The set of exclude patterns.</td>
-            </tr>
-        </table>
-    </section>
-    <section>
-        <title>Methods</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-            <tr>
-                <td><literal>from</literal></td>
-                <td><literal>AbstractCopyTask from(Object... sourcePaths)</literal></td>
-                <td>Specifies source files or directories to include.</td>
-            </tr>
-        </table>
-    </section>
-</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.plugins.idea.IdeaProject.xml b/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.plugins.idea.IdeaProject.xml
deleted file mode 100644
index 9e2d4fe..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/org.gradle.plugins.idea.IdeaProject.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<section>
-    <para>Generates an IDEA project file.</para>
-    <section>
-        <title>Properties</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Type</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-            <tr>
-                <td>javaVersion</td>
-                <td>The java version used for defining the project SDK.</td>
-            </tr>
-        </table>
-    </section>
-    <section>
-        <title>Methods</title>
-        <table>
-            <thead>
-                <tr>
-                    <td>Name</td>
-                    <td>Signature</td>
-                    <td>Description</td>
-                </tr>
-            </thead>
-        </table>
-    </section>
-</section>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/dsl/plugins.xml b/subprojects/gradle-docs/src/docs/userguide/dsl/plugins.xml
deleted file mode 100644
index 9f17cbd..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/dsl/plugins.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<plugins>
-    <plugin id="java" description="Java Plugin">
-        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.BasePluginConvention"/>
-        <extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.ReportingBasePluginConvention"/>
-        <!--<extends targetClass="org.gradle.api.Project" extensionClass="org.gradle.api.plugins.JavaPluginConvention"/>-->
-    </plugin>
-    <plugin id="groovy" description="Groovy Plugin">
-        <extends targetClass="org.gradle.api.tasks.SourceSet" extensionClass="org.gradle.api.tasks.GroovySourceSet"/>
-    </plugin>
-    <!--<plugin id="scala" description="Scala Plugin">-->
-        <!--<extends targetClass="org.gradle.api.tasks.SourceSet" extensionClass="org.gradle.api.tasks.ScalaSourceSet"/>-->
-    <!--</plugin>-->
-</plugins>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/eclipsePlugin.xml b/subprojects/gradle-docs/src/docs/userguide/eclipsePlugin.xml
index f95cde0..040d011 100644
--- a/subprojects/gradle-docs/src/docs/userguide/eclipsePlugin.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/eclipsePlugin.xml
@@ -138,7 +138,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.EclipseProject" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.EclipseProject"/></td>
                 <td>Generates the eclipse project file.</td>
             </tr>
             <tr>
@@ -148,7 +148,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.EclipseClasspath" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.EclipseClasspath"/></td>
                 <td>Generates the Eclipse classpath file.</td>
             </tr>
             <tr>
@@ -158,7 +158,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.EclipseJdt" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.EclipseJdt"/></td>
                 <td>Generates the JDT settings file.</td>
             </tr>
             <tr>
@@ -168,7 +168,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.EclipseWtp" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.EclipseWtp"/></td>
                 <td>Generates the WTP settings files.</td>
             </tr>
         </table>
@@ -422,9 +422,9 @@
                 <td>
                     <literal><code>beforeConfigured { arg -> }</code></literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Project" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Classpath" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Wtp" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Project"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Classpath"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Wtp"/></td>
                 <td>Gets called directly after the domain objects have been populated with the content of the
                     existing XML file (if there is one).</td>
             </tr>
@@ -432,9 +432,9 @@
                 <td>
                     <literal><code>whenConfigured { arg -> }</code></literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Project" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Classpath" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.eclipse.model.Wtp" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Project"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Classpath"/></td>
+                <td><apilink class="org.gradle.plugins.eclipse.model.Wtp"/></td>
                 <td>Gets called after the domain objects have been populated with the content of the
                     existing XML file and the content from the build script.</td>
             </tr>
diff --git a/subprojects/gradle-docs/src/docs/userguide/ideaPlugin.xml b/subprojects/gradle-docs/src/docs/userguide/ideaPlugin.xml
index 8fd56c7..fae0547 100644
--- a/subprojects/gradle-docs/src/docs/userguide/ideaPlugin.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/ideaPlugin.xml
@@ -123,7 +123,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.idea.IdeaProject" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.idea.IdeaProject"/></td>
                 <td>Generates the <filename>.ipr</filename> file. The Idea plugin adds this task only to the root project.</td>
             </tr>
             <tr>
@@ -133,7 +133,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.idea.IdeaModule" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.idea.IdeaModule"/></td>
                 <td>Generates the <filename>.iml</filename> file</td>
             </tr>
             <tr>
@@ -143,7 +143,7 @@
                 <td>
                     <literal>-</literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.idea.IdeaWorkspace" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.idea.IdeaWorkspace"/></td>
                 <td>Generates the <filename>.iws</filename> file</td>
             </tr>
         </table>
@@ -415,9 +415,9 @@
                 <td>
                     <literal><code>beforeConfigured { arg -> }</code></literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.idea.model.Project" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.idea.model.Module" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.idea.model.Workspace" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Project"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Module"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Workspace"/></td>
                 <td>Gets called directly after the domain objects have been populated with the content of the
                     existing XML file (if there is one).</td>
             </tr>
@@ -425,9 +425,9 @@
                 <td>
                     <literal><code>whenConfigured { arg -> }</code></literal>
                 </td>
-                <td><apilink class="org.gradle.plugins.idea.model.Project" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.idea.model.Module" lang="groovy"/></td>
-                <td><apilink class="org.gradle.plugins.idea.model.Workspace" lang="groovy"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Project"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Module"/></td>
+                <td><apilink class="org.gradle.plugins.idea.model.Workspace"/></td>
                 <td>Gets called after the domain objects have been populated with the content of the
                     existing XML file and the content from the build script.</td>
             </tr>
diff --git a/subprojects/gradle-docs/src/docs/userguide/installation.xml b/subprojects/gradle-docs/src/docs/userguide/installation.xml
index 819a357..ffe8bea 100644
--- a/subprojects/gradle-docs/src/docs/userguide/installation.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/installation.xml
@@ -43,6 +43,7 @@
 <itemizedlist>
     <listitem><para>The Gradle binaries.</para></listitem>
     <listitem><para>The user guide (HTML and PDF).</para></listitem>
+    <listitem><para>The DSL reference guide.</para></listitem>
     <listitem><para>The API documentation (Javadoc and Groovydoc).</para></listitem>
     <listitem>
         <para>Extensive samples, including the examples referenced in the user guide, along with some complete and more
@@ -83,15 +84,15 @@ some zip front ends for Mac OS X don't restore the file permissions properly.
 
 <screen>
 ------------------------------------------------------------
-Gradle 0.9-rc-3
+Gradle 0.9
 ------------------------------------------------------------
 
-Gradle build time: Monday, November 15, 2010 10:51:22 AM EST
-Groovy: 1.7.5
+Gradle build time: Sunday, 19 December 2010 12:50:06 PM EST
+Groovy: 1.7.6
 Ant: Apache Ant version 1.8.1 compiled on April 30 2010
 Ivy: 2.2.0
-JVM: 1.6.0_20 (Apple Inc. 16.3-b01-279)
-OS: Mac OS X 10.6.4 x86_64
+JVM: 1.6.0_22 (Sun Microsystems Inc. 17.1-b03)
+OS: Linux 2.6.35-23-generic amd64
 </screen>
 
 </section>
@@ -112,7 +113,7 @@ of the <command>gradle</command> or <command>gradlew</command> script.
 <title>Getting help</title>
 
 <para>You might check the user guide at <filename><replaceable>GRADLE_HOME</replaceable>/docs/userguide/userguide.html</filename>.
-It is also available on the <ulink url="website:userguide.html">Gradle web site</ulink>.
+It is also available on the <ulink url="website:documentation.html">Gradle web site</ulink>.
 Typing <command>gradle help</command> prints the command line help. Typing <command>gradle tasks</command> shows all the
 tasks of a Gradle build.
 </para>
diff --git a/subprojects/gradle-docs/src/docs/userguide/javaPlugin.xml b/subprojects/gradle-docs/src/docs/userguide/javaPlugin.xml
index 67dd18b..1b7725b 100644
--- a/subprojects/gradle-docs/src/docs/userguide/javaPlugin.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/javaPlugin.xml
@@ -126,7 +126,7 @@
                 <td>
                     <literal>compile</literal>
                 </td>
-                <td><apilink class="org.gradle.api.tasks.bundling.Jar" lang="groovy"/></td>
+                <td><apilink class="org.gradle.api.tasks.bundling.Jar"/></td>
                 <td>Assembles the JAR file</td>
             </tr>
             <tr>
@@ -660,7 +660,7 @@
                 <td>
                     <literal>manifest</literal>
                 </td>
-                <td><apilink class="org.gradle.api.java.archives.Manifest" lang="java"/></td>
+                <td><apilink class="org.gradle.api.java.archives.Manifest"/></td>
                 <td>an empty manifest</td>
                 <td>The manifest to include in all JAR files.</td>
             </tr>
@@ -678,9 +678,9 @@
         </table>
 
         <para>
-            These properties are provided by convention objects of type <apilink class="org.gradle.api.plugins.JavaPluginConvention" lang="groovy"/>,
-            <apilink class="org.gradle.api.plugins.BasePluginConvention" lang="groovy"/> and
-            <apilink class="org.gradle.api.plugins.ReportingBasePluginConvention" lang="groovy"/>.
+            These properties are provided by convention objects of type <apilink class="org.gradle.api.plugins.JavaPluginConvention"/>,
+            <apilink class="org.gradle.api.plugins.BasePluginConvention"/> and
+            <apilink class="org.gradle.api.plugins.ReportingBasePluginConvention"/>.
         </para>
     </section>
 
@@ -1211,7 +1211,7 @@
         <section id='sub:manifest'>
             <title>Manifest</title>
             <para>Each jar or war object has a <literal>manifest</literal>
-                property with a separate instance of <apilink class="org.gradle.api.java.archives.Manifest" lang="java"/>.
+                property with a separate instance of <apilink class="org.gradle.api.java.archives.Manifest"/>.
                 When the archive is generated, a corresponding <literal>MANIFEST.MF</literal> file is written into the
                 archive.
             </para>
diff --git a/subprojects/gradle-docs/src/docs/userguide/osgi.xml b/subprojects/gradle-docs/src/docs/userguide/osgi.xml
index 8ce3203..3831d69 100644
--- a/subprojects/gradle-docs/src/docs/userguide/osgi.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/osgi.xml
@@ -62,7 +62,7 @@
         <section>
             <title>Convention methods</title>
 
-            <para>The OSGi plugin adds the following methods. For more details, see the javadoc of the convention
+            <para>The OSGi plugin adds the following methods. For more details, see the API documentation of the convention
                 object.
             </para>
             <table>
diff --git a/subprojects/gradle-docs/src/docs/userguide/projectReports.xml b/subprojects/gradle-docs/src/docs/userguide/projectReports.xml
index 4dd42ea..6096703 100644
--- a/subprojects/gradle-docs/src/docs/userguide/projectReports.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/projectReports.xml
@@ -156,7 +156,7 @@ apply plugin: 'project-report'
             </tr>
         </table>
 
-        <para>These convention properties are provided by a convention object of type <apilink class="org.gradle.api.plugins.ProjectReportsPluginConvention" lang="groovy"/>.</para>
+        <para>These convention properties are provided by a convention object of type <apilink class="org.gradle.api.plugins.ProjectReportsPluginConvention"/>.</para>
     </section>
     
 </chapter>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/standardPlugins.xml b/subprojects/gradle-docs/src/docs/userguide/standardPlugins.xml
index b7c9280..d0b6800 100644
--- a/subprojects/gradle-docs/src/docs/userguide/standardPlugins.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/standardPlugins.xml
@@ -205,7 +205,7 @@
         <para>These plugins form the basic building blocks which the other plugins are assembled from. They are
             available for you to use in your build files, and are listed here for completeness. However, be aware that
             they are not yet considered part of Gradle's public API. As such, these plugins are not documented in the
-            user guide. You might refer to their Javadoc to learn more about them.
+            user guide. You might refer to their API documentation to learn more about them.
         </para>
         <table>
             <title>Base plugins</title>
diff --git a/subprojects/gradle-docs/src/docs/userguide/standardTasks.xml b/subprojects/gradle-docs/src/docs/userguide/standardTasks.xml
deleted file mode 100644
index 0f45dfa..0000000
--- a/subprojects/gradle-docs/src/docs/userguide/standardTasks.xml
+++ /dev/null
@@ -1,159 +0,0 @@
-<chapter id="standard_tasks">
-    <title>Standard Gradle tasks</title>
-    <para>There are a number of tasks included in the Gradle distribution. These are listed below.
-    </para>
-    <table>
-        <title>Standard tasks</title>
-        <thead>
-            <tr>
-                <td>Task class</td>
-                <td>Description</td>
-            </tr>
-        </thead>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.antlr.AntlrTask'/></td>
-            <td>Generates parsers from Antlr grammars.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.quality.Checkstyle'/></td>
-            <td>Runs Checkstyle against some source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.quality.CodeNarc'/></td>
-            <td>Runs CodeNarc against some source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.compile.Compile'/></td>
-            <td>Compiles Java source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Copy'/></td>
-            <td>Copies files into a destination directory. See <xref linkend="sec:copying_files"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Delete'/></td>
-            <td>Deletes files or directories.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Directory' lang='groovy'/></td>
-            <td>Creates a directory. See <xref linkend="sec:directory_creation"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.diagnostics.DependencyReportTask'/></td>
-            <td>Displays the dependency tree for a project.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.eclipse.EclipseClasspath' lang="groovy"/></td>
-            <td>Generates an Eclipse .classpath file.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.eclipse.EclipseJdt' lang="groovy"/></td>
-            <td>Generates configuration files for Eclipse JDT.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.eclipse.EclipseProject' lang="groovy"/></td>
-            <td>Generates an Eclipse .project file.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.eclipse.EclipseWtp' lang="groovy"/></td>
-            <td>Generates configuration files for Eclipse WTP.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Exec'/></td>
-            <td>Executes a command line process.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.GradleBuild'/></td>
-            <td>Executes a Gradle build. See <xref linkend="sec:external_build"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.compile.GroovyCompile'/></td>
-            <td>Compiles Groovy and Java source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.javadoc.Groovydoc'/></td>
-            <td>Generates HTML API documentation for Groovy and Java classes.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.idea.IdeaModule' lang="groovy"/></td>
-            <td>Generates an IDEA module file.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.idea.IdeaProject' lang="groovy"/></td>
-            <td>Generates an IDEA project file.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.plugins.idea.IdeaWorkspace' lang="groovy"/></td>
-            <td>Generates an IDEA workspace file.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.bundling.Jar' lang='groovy'/></td>
-            <td>Assembles a JAR archive. See <xref linkend="sec:archives"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.javadoc.Javadoc'/></td>
-            <td>Generates HTML API documentation for Java classes.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.JavaExec'/></td>
-            <td>Executes a Java application.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.jetty.JettyRun'/></td>
-            <td>Deploys an exploded web application to an embedded Jetty web container.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.jetty.JettyRunWar'/></td>
-            <td>Deploys a WAR to an embedded Jetty web container.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.plugins.jetty.JettyStop'/></td>
-            <td>Stops the embedded Jetty web container.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.diagnostics.PropertyReportTask'/></td>
-            <td>Displays the properties of a project.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.scala.ScalaCompile'/></td>
-            <td>Compiles Scala and Java source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.scala.ScalaDoc'/></td>
-            <td>Generates HTML API documentation for Scala source files.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Sync'/></td>
-            <td>Synchronises the contents of a destination directory with some source. See <xref linkend="sec:sync_task"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.bundling.Tar'/></td>
-            <td>Assembles a TAR archive. See <xref linkend="sec:archives"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.diagnostics.TaskReportTask'/></td>
-            <td>Displays a list of tasks in the project.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.testing.Test'/></td>
-            <td>Executes tests.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.Upload'/></td>
-            <td>Uploads the artifacts of a configuration to a set of repositories.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.bundling.War' lang='groovy'/></td>
-            <td>Assembles a WAR archive. See <xref linkend="sec:archives"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.wrapper.Wrapper'/></td>
-            <td>Generates scripts (for *nix and windows) which enable you to build your project with Gradle, without
-                having to install Gradle. See <xref linkend="gradle_wrapper"/>.</td>
-        </tr>
-        <tr>
-            <td><apilink class='org.gradle.api.tasks.bundling.Zip'/></td>
-            <td>Assembles a ZIP archive. See <xref linkend="sec:archives"/>.</td>
-        </tr>
-    </table>
-</chapter>
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/docs/userguide/tutorials.xml b/subprojects/gradle-docs/src/docs/userguide/tutorials.xml
index 9db44f8..93ecb71 100644
--- a/subprojects/gradle-docs/src/docs/userguide/tutorials.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/tutorials.xml
@@ -67,6 +67,6 @@
     </section>
     <section condition="website">
         <title>Where to next?</title>
-        <para>There are more tutorials and plenty of reference material in the <ulink url="website:userguide.html">user guide</ulink>.</para>
+        <para>There are more tutorials and plenty of reference material in the <ulink url="website:documentation.html">user guide</ulink>.</para>
     </section>
 </chapter>
diff --git a/subprojects/gradle-docs/src/docs/userguide/userguide.xml b/subprojects/gradle-docs/src/docs/userguide/userguide.xml
index 4bf55dc..d185dda 100644
--- a/subprojects/gradle-docs/src/docs/userguide/userguide.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/userguide.xml
@@ -55,7 +55,6 @@
     <xi:include href='ant.xml'/>
     <xi:include href='plugins.xml'/>
     <xi:include href='standardPlugins.xml'/>
-    <xi:include href='standardTasks.xml'/>
     <xi:include href='javaPlugin.xml'/>
     <xi:include href='groovyPlugin.xml'/>
     <xi:include href='scalaPlugin.xml'/>
@@ -80,7 +79,7 @@
     <xi:include href='gradleWrapper.xml'/>
     <xi:include href='embedding.xml'/>
     <!-- this is generated -->
-    <xi:include href='../../../build/src/docbook/samplesList.xml'/>
+    <xi:include href='../../../build/src/samplesList.xml'/>
     <xi:include href='potentialTraps.xml'/>
     <xi:include href='commandLine.xml'/>
     <xi:include href='ideSupport.xml'/>
diff --git a/subprojects/gradle-docs/src/docs/userguide/warPlugin.xml b/subprojects/gradle-docs/src/docs/userguide/warPlugin.xml
index 1baada5..8a5cd89 100644
--- a/subprojects/gradle-docs/src/docs/userguide/warPlugin.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/warPlugin.xml
@@ -47,7 +47,7 @@
                 <td>
                     <literal>compile</literal>
                 </td>
-                <td><apilink class="org.gradle.api.tasks.bundling.War" lang="groovy"/></td>
+                <td><apilink class="org.gradle.api.tasks.bundling.War"/></td>
                 <td>Assembles the application WAR file.</td>
             </tr>
         </table>
@@ -147,7 +147,7 @@
             </tr>
         </table>
 
-        <para>These properties are provided by a <apilink class="org.gradle.api.plugins.WarPluginConvention" lang="groovy"/>
+        <para>These properties are provided by a <apilink class="org.gradle.api.plugins.WarPluginConvention"/>
             convention object.
         </para>
     </section>
@@ -169,7 +169,7 @@
                 </para>
             </footnote>
             configuration are copied to <literal>WEB-INF/lib</literal>.</para>
-        <para>Have also a look at <apilink class="org.gradle.api.tasks.bundling.War" lang="groovy"/>.</para>
+        <para>Have also a look at <apilink class="org.gradle.api.tasks.bundling.War"/>.</para>
     </section>
     <section id='sec:customizing'>
         <title>Customizing</title>
diff --git a/subprojects/gradle-docs/src/docs/userguide/webTutorial.xml b/subprojects/gradle-docs/src/docs/userguide/webTutorial.xml
index f1ac942..6a8a9fc 100644
--- a/subprojects/gradle-docs/src/docs/userguide/webTutorial.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/webTutorial.xml
@@ -50,7 +50,7 @@
         </sample>
         <para>This also applies the War plugin to your project. Running <userinput>gradle jettyRun</userinput> will
             run your web application in an embedded Jetty web container. Running <userinput>gradle jettyRunWar</userinput>
-            will build and test the WAR file, and then run it in an embedded web container.
+            will build the WAR file, and then run it in an embedded web container.
         </para>
         <para>TODO: which url, configure port, uses source files in place and can edit your files and reload.</para>
     </section>
diff --git a/subprojects/gradle-docs/src/docs/userguide/workingWithFiles.xml b/subprojects/gradle-docs/src/docs/userguide/workingWithFiles.xml
index 82d81fb..fe364a4 100644
--- a/subprojects/gradle-docs/src/docs/userguide/workingWithFiles.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/workingWithFiles.xml
@@ -22,7 +22,7 @@
     <section id="sec:locating_files">
         <title>Locating files</title>
         <para>You can locate a file relative to the project directory using the
-            <apilink class="org.gradle.api.Project" method="file"/> method.
+            <apilink class="org.gradle.api.Project" method="file(java.lang.Object)"/> method.
         </para>
         <sample id="resolveFile" dir="userguide/files/file" title="Locating files">
             <sourcefile file="build.gradle"/>
@@ -54,7 +54,7 @@
 
         <para>
             One way to obtain a <literal>FileCollection</literal> instance is to use the
-            <apilink class="org.gradle.api.Project" method="files"/> method. You can pass this method any number of
+            <apilink class="org.gradle.api.Project" method="files(java.lang.Object...)"/> method. You can pass this method any number of
             objects, which are then converted into a set of <classname>File</classname> objects. The
             <literal>files()</literal> method accepts any type of object as its parameters. These are evaluated relative
             to the project directory, as for the <literal>file()</literal> method, described in <xref linkend="sec:locating_files"/>.
@@ -111,7 +111,7 @@
 
         <para>
             One way to obtain a <literal>FileTree</literal> instance is to use the
-            <apilink class="org.gradle.api.Project" method="fileTree"/> method.
+            <apilink class="org.gradle.api.Project" method="fileTree(java.util.Map)"/> method.
             This creates a <literal>FileTree</literal> defined with a base directory, and optionally some Ant-style
             include and exclude patterns.
         </para>
@@ -173,8 +173,8 @@
             the files to. You may also specify how to transform the files as they are copied. You do all this using a
             <firstterm>copy spec</firstterm>. A copy spec is represented by the <apilink class="org.gradle.api.file.CopySpec"/> interface. The
             <literal>Copy</literal> task implements this interface.
-            You specify the source files using the <apilink class="org.gradle.api.file.CopySpec" method="from"/>
-            method. To specify the destination directory, you use the <apilink class="org.gradle.api.file.CopySpec" method="into"/>
+            You specify the source files using the <apilink class="org.gradle.api.file.CopySpec" method="from(java.lang.Object...)"/>
+            method. To specify the destination directory, you use the <apilink class="org.gradle.api.file.CopySpec" method="into(java.lang.Object)"/>
             method.
         </para>
         <sample id="copy" dir="userguide/files/copy" title="Copying files using the copy task">
@@ -246,8 +246,8 @@
             Archives are created using the various archive tasks:
             <apilink class="org.gradle.api.tasks.bundling.Zip"/>,
             <apilink class="org.gradle.api.tasks.bundling.Tar"/>,
-            <apilink class="org.gradle.api.tasks.bundling.Jar" lang="groovy"/>, and
-            <apilink class="org.gradle.api.tasks.bundling.War" lang="groovy"/>.
+            <apilink class="org.gradle.api.tasks.bundling.Jar"/>, and
+            <apilink class="org.gradle.api.tasks.bundling.War"/>.
             They all work the same way, so let's look at how you create a ZIP file.
         </para>
         <sample id="createZip" dir="userguide/files/archives" title="Creating a ZIP archive">
diff --git a/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml b/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
index 6d6f960..fbb45e4 100644
--- a/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
@@ -30,7 +30,7 @@
             <para>Don't forget that your build script is simply Groovy code that drives the Gradle API. And the
                 <apilink class='org.gradle.api.Project'/> interface is your starting point for accessing everything
                 in the Gradle API. So, if you're wondering what 'tags' are available in your build script, you can
-                start with the javadocs for the <classname>Project</classname> interface.
+                start with the documentation for the <classname>Project</classname> interface.
             </para>
         </tip>
         <itemizedlist>
diff --git a/subprojects/gradle-docs/src/samples/codeQuality/build.gradle b/subprojects/gradle-docs/src/samples/codeQuality/build.gradle
index 7a3f852..54f1631 100644
--- a/subprojects/gradle-docs/src/samples/codeQuality/build.gradle
+++ b/subprojects/gradle-docs/src/samples/codeQuality/build.gradle
@@ -8,6 +8,6 @@ repositories {
 }
 
 dependencies {
-    groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.5'
+    groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.6'
     testCompile group: 'junit', name: 'junit', version: '4.7'
 }
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/groovy/customizedLayout/build.gradle b/subprojects/gradle-docs/src/samples/groovy/customizedLayout/build.gradle
index 8296c8a..7f14af5 100644
--- a/subprojects/gradle-docs/src/samples/groovy/customizedLayout/build.gradle
+++ b/subprojects/gradle-docs/src/samples/groovy/customizedLayout/build.gradle
@@ -5,7 +5,7 @@ repositories {
 }
 
 dependencies {
-    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.5'
+    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.6'
     testCompile group: 'junit', name: 'junit', version: '4.7'
 }
 
diff --git a/subprojects/gradle-docs/src/samples/groovy/mixedJavaAndGroovy/build.gradle b/subprojects/gradle-docs/src/samples/groovy/mixedJavaAndGroovy/build.gradle
index 0d219f9..6402f6a 100644
--- a/subprojects/gradle-docs/src/samples/groovy/mixedJavaAndGroovy/build.gradle
+++ b/subprojects/gradle-docs/src/samples/groovy/mixedJavaAndGroovy/build.gradle
@@ -6,6 +6,6 @@ repositories {
 }
 
 dependencies {
-    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.5'
+    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.6'
     testCompile group: 'junit', name: 'junit', version: '4.7'
 }
diff --git a/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/build.gradle b/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/build.gradle
index e61eb68..e336f79 100644
--- a/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/build.gradle
+++ b/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/build.gradle
@@ -4,7 +4,7 @@ group = 'org.gradle'
 version = '1.0'
 
 dependencies {
-    groovy 'org.codehaus.groovy:groovy-all:1.7.5'
+    groovy 'org.codehaus.groovy:groovy-all:1.7.6'
     compile project(':groovycDetector')
     testCompile 'junit:junit:4.7'
 }
diff --git a/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/src/test/groovy/org/gradle/VersionTest.groovy b/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/src/test/groovy/org/gradle/VersionTest.groovy
index 92be75a..9b42126 100644
--- a/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/src/test/groovy/org/gradle/VersionTest.groovy
+++ b/subprojects/gradle-docs/src/samples/groovy/multiproject/testproject/src/test/groovy/org/gradle/VersionTest.groovy
@@ -7,7 +7,7 @@ class GroovycVersionTest {
   def groovycVersion
 
   @Test
-  void versionShouldBe1_7_5() {
-    assertEquals("1.7.5", groovycVersion)
+  void versionShouldBe1_7_6() {
+    assertEquals("1.7.6", groovycVersion)
   }
 }
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/groovy/quickstart/build.gradle b/subprojects/gradle-docs/src/samples/groovy/quickstart/build.gradle
index 5277b60..3e91669 100644
--- a/subprojects/gradle-docs/src/samples/groovy/quickstart/build.gradle
+++ b/subprojects/gradle-docs/src/samples/groovy/quickstart/build.gradle
@@ -9,7 +9,7 @@ repositories {
 }
 
 dependencies {
-    groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.5'
+    groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.6'
 // END SNIPPET groovy-dependency
     testCompile group: 'junit', name: 'junit', version: '4.7'
 // START SNIPPET groovy-dependency
diff --git a/subprojects/gradle-docs/src/samples/groovy/quickstart/src/test/groovy/org/gradle/PersonTest.groovy b/subprojects/gradle-docs/src/samples/groovy/quickstart/src/test/groovy/org/gradle/PersonTest.groovy
index b698368..ad562e6 100644
--- a/subprojects/gradle-docs/src/samples/groovy/quickstart/src/test/groovy/org/gradle/PersonTest.groovy
+++ b/subprojects/gradle-docs/src/samples/groovy/quickstart/src/test/groovy/org/gradle/PersonTest.groovy
@@ -16,7 +16,7 @@ class PersonTest {
     }
 
     @Test public void usingCorrectVersionOfGroovy() {
-        assertEquals('1.7.5', InvokerHelper.version)
+        assertEquals('1.7.6', InvokerHelper.version)
     }
     
     @Test public void testResourcesAreAvailable() {
diff --git a/subprojects/gradle-docs/src/samples/osgi/build.gradle b/subprojects/gradle-docs/src/samples/osgi/build.gradle
index b9f0c1b..62f2367 100644
--- a/subprojects/gradle-docs/src/samples/osgi/build.gradle
+++ b/subprojects/gradle-docs/src/samples/osgi/build.gradle
@@ -12,7 +12,7 @@ repositories {
 }
 
 dependencies {
-    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.5'
+    groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.7.6'
     compile group: 'org.eclipse', name: 'osgi', version: '3.4.3.R34x_v20081215-1030'
 }
 
diff --git a/subprojects/gradle-docs/src/samples/userguide/artifacts/externalDependencies/build.gradle b/subprojects/gradle-docs/src/samples/userguide/artifacts/externalDependencies/build.gradle
index 1bbe7d4..0dc3ad4 100644
--- a/subprojects/gradle-docs/src/samples/userguide/artifacts/externalDependencies/build.gradle
+++ b/subprojects/gradle-docs/src/samples/userguide/artifacts/externalDependencies/build.gradle
@@ -63,7 +63,7 @@ dependencies {
 
 //START SNIPPET client-modules
 dependencies {
-    runtime module("org.codehaus.groovy:groovy-all:1.7.5") {
+    runtime module("org.codehaus.groovy:groovy-all:1.7.6") {
         dependency("commons-cli:commons-cli:1.0") {
             transitive = false
         }
@@ -82,7 +82,7 @@ dependencies {
 //END SNIPPET file-dependencies
 
 //START SNIPPET list-grouping
-List groovy = ["org.codehaus.groovy:groovy-all:1.7.5 at jar",
+List groovy = ["org.codehaus.groovy:groovy-all:1.7.6 at jar",
                "commons-cli:commons-cli:1.0 at jar",
                "org.apache.ant:ant:1.7.0 at jar"]
 List hibernate = ['org.hibernate:hibernate:3.0.5 at jar', 'somegroup:someorg:1.0 at jar']
diff --git a/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/externalDependency/build.gradle b/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/externalDependency/build.gradle
index cb5731a..0aace0e 100644
--- a/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/externalDependency/build.gradle
+++ b/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/externalDependency/build.gradle
@@ -12,6 +12,6 @@ buildscript {
 // END SNIPPET declare-classpath
 
 task encode << {
-    def byte[] encodedString = new Base64().encode('hello world\n' as byte[])
+    def byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
     println new String(encodedString)
 }
diff --git a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectReports/build.gradle b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectReports/build.gradle
index c2d2433..8df32e7 100644
--- a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectReports/build.gradle
+++ b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectReports/build.gradle
@@ -63,7 +63,7 @@ project(':api') {
 description = 'The shared API for the application'
 // END SNIPPET project-description
     dependencies {
-        compile "org.codehaus.groovy:groovy-all:1.7.5"
+        compile "org.codehaus.groovy:groovy-all:1.7.6"
     }
 }
 
diff --git a/subprojects/gradle-docs/src/samples/userguideOutput/dependencyListReport.out b/subprojects/gradle-docs/src/samples/userguideOutput/dependencyListReport.out
index 79cf988..1ccaad8 100644
--- a/subprojects/gradle-docs/src/samples/userguideOutput/dependencyListReport.out
+++ b/subprojects/gradle-docs/src/samples/userguideOutput/dependencyListReport.out
@@ -10,7 +10,7 @@ Project :api - The shared API for the application
 ------------------------------------------------------------
 
 compile
-\--- org.codehaus.groovy:groovy-all:1.7.5 [default]
+\--- org.codehaus.groovy:groovy-all:1.7.6 [default]
 
 ------------------------------------------------------------
 Project :webapp - The Web application implementation
@@ -18,5 +18,5 @@ Project :webapp - The Web application implementation
 
 compile
 +--- projectReports:api:1.0-SNAPSHOT [compile]
-|    \--- org.codehaus.groovy:groovy-all:1.7.5 [default]
+|    \--- org.codehaus.groovy:groovy-all:1.7.6 [default]
 \--- commons-io:commons-io:1.2 [default]
diff --git a/subprojects/gradle-docs/src/samples/userguideOutput/projectListReport.out b/subprojects/gradle-docs/src/samples/userguideOutput/projectListReport.out
index e0ede51..a29ff66 100644
--- a/subprojects/gradle-docs/src/samples/userguideOutput/projectListReport.out
+++ b/subprojects/gradle-docs/src/samples/userguideOutput/projectListReport.out
@@ -1,4 +1,8 @@
 
+------------------------------------------------------------
+Root Project
+------------------------------------------------------------
+
 Root project 'projectReports'
 +--- Project ':api' - The shared API for the application
 \--- Project ':webapp' - The Web application implementation
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseClasspath.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseClasspath.groovy
index 82bb853..5aa97a5 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseClasspath.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseClasspath.groovy
@@ -23,7 +23,7 @@ import org.gradle.plugins.eclipse.model.Container
 import org.gradle.plugins.eclipse.model.internal.ClasspathFactory
 
 /**
- * Generates an Eclipse <i>.classpath</i> file.
+ * Generates an Eclipse <code>.classpath</code> file.
  *
  * @author Hans Dockter
  */
@@ -46,7 +46,7 @@ public class EclipseClasspath extends XmlGeneratorTask<Classpath> {
     /**
      * The variables to be used for replacing absolute paths in classpath entries.
      */
-    Map variables = [:]
+    Map<String, File> variables = [:]
 
     /**
      * Containers to be added to the classpath
@@ -93,7 +93,7 @@ public class EclipseClasspath extends XmlGeneratorTask<Classpath> {
      *
      * @param variables A map where the keys are the variable names and the values are the variable values.
      */
-    void variables(Map variables) {
+    void variables(Map<String, File> variables) {
         assert variables != null
         this.variables.putAll variables
     }
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseJdt.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseJdt.groovy
index bee92dc..acce5d8 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseJdt.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseJdt.groovy
@@ -21,15 +21,17 @@ import org.gradle.api.tasks.GeneratorTask
 import org.gradle.plugins.eclipse.model.Jdt
 
 /**
- * Generates the Eclipse JDT settings file {@code .settings/org.eclipse.jdt.core.prefs}.
+ * Generates the Eclipse JDT configuration file.
  */
 class EclipseJdt extends GeneratorTask<Jdt> {
-    File inputFile
-
-    File outputFile
-
+    /**
+     * The source Java language level.
+     */
     JavaVersion sourceCompatibility
 
+    /**
+     * The target JVM to generate {@code .class} files for.
+     */
     JavaVersion targetCompatibility
 
     EclipseJdt() {
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseProject.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseProject.groovy
index 6285da7..0ed79bb 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseProject.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseProject.groovy
@@ -23,7 +23,7 @@ import org.gradle.plugins.eclipse.model.Link
 import org.gradle.plugins.eclipse.model.Project
 
 /**
- * Generates an Eclipse <i>.project</i> file.
+ * Generates an Eclipse <code>.project</code> file.
  *
  * @author Hans Dockter
  */
@@ -115,7 +115,7 @@ public class EclipseProject extends XmlGeneratorTask<Project> {
      *
      * @param args A maps with the args for the link. Legal keys for the map are name, type, location and locationUri.
      */
-    void link(Map args) {
+    void link(Map<String, String> args) {
         def illegalArgs = LINK_ARGUMENTS - args.keySet()
         if (illegalArgs) {
             throw new InvalidUserDataException("You provided illegal argument for a link: " + illegalArgs)
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseWtp.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseWtp.groovy
index 9bc4e14..65d8546 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseWtp.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/EclipseWtp.groovy
@@ -41,10 +41,10 @@ public class EclipseWtp extends ConventionTask {
      */
     File orgEclipseWstCommonComponentInputFile
 
-    @OutputFile
     /**
      * The output file for the org.eclipse.wst.common.component metadata.
      */
+    @OutputFile
     File orgEclipseWstCommonComponentOutputFile
 
     /**
@@ -53,10 +53,10 @@ public class EclipseWtp extends ConventionTask {
      */
     File orgEclipseWstCommonProjectFacetCoreInputFile
 
-    @OutputFile
     /**
      * The output file for the org.eclipse.wst.common.project.facet.core metadata.
      */
+    @OutputFile
     File orgEclipseWstCommonProjectFacetCoreOutputFile
 
     /**
@@ -90,7 +90,7 @@ public class EclipseWtp extends ConventionTask {
      * The variables to be used for replacing absolute path in dependent-module elements of
      * the org.eclipse.wst.common.component file.
      */
-    Map<String, String> variables = [:]
+    Map<String, File> variables = [:]
 
     /**
      * Additional wb-resource elements.
@@ -128,7 +128,7 @@ public class EclipseWtp extends ConventionTask {
      *
      * @param args A map that must contain a name and version key with corresponding values.
      */
-    void facet(Map args) {
+    void facet(Map<String, ?> args) {
         setFacets(getFacets() + [ConfigureUtil.configureByMap(args, new Facet())])
     }
 
@@ -138,7 +138,7 @@ public class EclipseWtp extends ConventionTask {
      *
      * @param variables A map where the keys are the variable names and the values are the variable values.
      */
-    void variables(Map variables) {
+    void variables(Map<String, File> variables) {
         assert variables != null
         this.variables.putAll variables
     }
@@ -148,7 +148,7 @@ public class EclipseWtp extends ConventionTask {
      *
      * @param args A map that must contain a name and value key with corresponding values.
      */
-    void property(Map args) {
+    void property(Map<String, String> args) {
         properties.add(new WbProperty(args.name, args.value))
     }
 
@@ -157,18 +157,30 @@ public class EclipseWtp extends ConventionTask {
      *
      * @param args A map that must contain a deployPath and sourcePath key with corresponding values.
      */
-    void resource(Map args) {
+    void resource(Map<String, String> args) {
         resources.add(new WbResource(args.deployPath, args.sourcePath))
     }
 
+    /**
+     * Adds a closure to be called when the XML content for each file has been generated, but before the content is
+     * written to the file.
+     */
     void withXml(Closure closure) {
         withXmlActions.add(closure);
     }
 
+    /**
+     * Adds a closure to be called when the model has been loaded from the input files, and before this task has
+     * configured the model.
+     */
     void beforeConfigured(Closure closure) {
         beforeConfiguredActions.add(closure);
     }
 
+    /**
+     * Adds a closure to be called after this task has configured model, and before it generates the XML content for the
+     * files.
+     */
     void whenConfigured(Closure closure) {
         whenConfiguredActions.add(closure);
     }
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/ClasspathFactory.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/ClasspathFactory.groovy
index 6231a99..d526293 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/ClasspathFactory.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/ClasspathFactory.groovy
@@ -102,7 +102,7 @@ class ClasspathFactory {
         moduleLibraries
     }
 
-    private def getSelfResolvingFiles(Collection dependencies, Map variables) {
+    private def getSelfResolvingFiles(Collection dependencies, Map<String, File> variables) {
         dependencies.inject([] as LinkedHashSet) { result, SelfResolvingDependency selfResolvingDependency ->
             result.addAll(selfResolvingDependency.resolve().collect { File file ->
                 createLibraryEntry(file, null, null, variables)
@@ -111,7 +111,7 @@ class ClasspathFactory {
         }
     }
 
-    AbstractLibrary createLibraryEntry(File binary, File source, File javadoc, Map variables) {
+    AbstractLibrary createLibraryEntry(File binary, File source, File javadoc, Map<String, File> variables) {
         def usedVariableEntry = variables.find { String name, File value -> binary.canonicalPath.startsWith(value.canonicalPath) }
         if (usedVariableEntry) {
             String name = usedVariableEntry.key
diff --git a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/WtpFactory.groovy b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/WtpFactory.groovy
index bdf9e85..92697ad 100644
--- a/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/WtpFactory.groovy
+++ b/subprojects/gradle-eclipse/src/main/groovy/org/gradle/plugins/eclipse/model/internal/WtpFactory.groovy
@@ -90,9 +90,9 @@ class WtpFactory {
         }
     }
 
-    WbDependentModule createWbDependentModuleEntry(File file, Map variables) {
+    WbDependentModule createWbDependentModuleEntry(File file, Map<String, File> variables) {
         def usedVariableEntry = variables.find { name, value -> file.canonicalPath.startsWith(value.canonicalPath) }
-        String handleSnippet = null;
+        String handleSnippet;
         if (usedVariableEntry) {
             handleSnippet = "var/$usedVariableEntry.key/${file.canonicalPath.substring(usedVariableEntry.value.canonicalPath.length())}"
         } else {
diff --git a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaModule.groovy b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaModule.groovy
index 8a3a078..d1ee8de 100644
--- a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaModule.groovy
+++ b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaModule.groovy
@@ -28,6 +28,7 @@ import org.gradle.api.artifacts.ResolvedConfiguration
 import org.gradle.api.artifacts.SelfResolvingDependency
 import org.gradle.api.artifacts.ResolvedDependency
 import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.Configuration
 
 /**
  * Generates an IDEA module file.
@@ -36,64 +37,64 @@ import org.gradle.api.artifacts.Dependency
  */
 public class IdeaModule extends XmlGeneratorTask<Module> {
     /**
-     * The content root directory of the module. Must not be null.
+     * The content root directory of the module.
      */
     @InputFiles
     File moduleDir
 
     /**
-     * The dirs containing the production sources. Must not be null.
+     * The dirs containing the production sources.
      */
     @InputFiles
-    Set sourceDirs
+    Set<File> sourceDirs
 
     /**
-     * The dirs containing the test sources. Must not be null.
+     * The dirs containing the test sources.
      */
     @InputFiles
-    Set testSourceDirs
+    Set<File> testSourceDirs
 
     /**
-     * The dirs to be excluded by idea. Must not be null.
+     * The dirs to be excluded by idea.
      */
     @InputFiles
-    Set excludeDirs
+    Set<File> excludeDirs
 
     /**
-     * The idea output dir for the production sources. If null no entry for output dirs is created.
+     * The idea output dir for the production sources. If {@code null} no entry for output dirs is created.
      */
     @InputFiles @Optional
     File outputDir
 
     /**
-     * The idea output dir for the test sources. If null no entry for test output dirs is created.
+     * The idea output dir for the test sources. If {@code null} no entry for test output dirs is created.
      */
     @InputFiles @Optional
     File testOutputDir
 
     /**
-     * If this is null the value of the existing or default ipr XML (inherited) is used. If it is set
-     * to <code>inherited</code>, the project SDK is used. Otherwise the SDK for the corresponding
+     * The JDK to use for this module. If this is {@code null} the value of the existing or default ipr XML (inherited)
+     * is used. If it is set to <code>inherited</code>, the project SDK is used. Otherwise the SDK for the corresponding
      * value of java version is used for this module
      */
     @Input @Optional
     String javaVersion = org.gradle.plugins.idea.model.Module.INHERITED
 
     /**
-     * Whether to download and add sources associated with the dependency jars. Defaults to true. 
+     * Whether to download and add sources associated with the dependency jars.
      */
     @Input
     boolean downloadSources = true
 
     /**
-     * Whether to download and add javadoc associated with the dependency jars. Defaults to false.
+     * Whether to download and add javadoc associated with the dependency jars.
      */
     @Input
     boolean downloadJavadoc = false
 
     /**
      * The variables to be used for replacing absolute paths in the iml entries. For example, you might add a
-     * GRADLE_USER_HOME variable to point to the Gradle user home dir.
+     * {@code GRADLE_USER_HOME} variable to point to the Gradle user home dir.
      */
     Map<String, File> variables = [:]
 
@@ -102,7 +103,7 @@ public class IdeaModule extends XmlGeneratorTask<Module> {
      * The values of those keys are sets of  {@link org.gradle.api.artifacts.Configuration}  objects. The files of the
      * plus configurations are added minus the files from the minus configurations.
      */
-    Map scopes = [:]
+    Map<String, Map<String, Configuration>> scopes = [:]
 
     @Override protected Module create() {
         return new Module(xmlTransformer, pathFactory)
@@ -193,12 +194,12 @@ public class IdeaModule extends XmlGeneratorTask<Module> {
         }
     }
 
-    private Set getScopeDependencies(Map configurations, Closure filter) {
+    private Set getScopeDependencies(Map<String, Configuration> configurations, Closure filter) {
         Set firstLevelDependencies = new LinkedHashSet()
-        configurations.plus.each { configuration ->
+        configurations.plus.each { Configuration configuration ->
             firstLevelDependencies.addAll(configuration.getAllDependencies().findAll(filter))
         }
-        configurations.minus.each { configuration ->
+        configurations.minus.each { Configuration configuration ->
             configuration.getAllDependencies().findAll(filter).each { minusDep ->
                 // This deals with dependencies that are defined in different scopes with different
                 // artifacts. Right now we accept the fact, that in such a situation some artifacts
diff --git a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaProject.groovy b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaProject.groovy
index feb8ff1..aba3d25 100644
--- a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaProject.groovy
+++ b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/IdeaProject.groovy
@@ -28,10 +28,10 @@ import org.gradle.plugins.idea.model.Project
  */
 public class IdeaProject extends XmlGeneratorTask<Project> {
     /**
-     * The subprojects that should be mapped to modules in the ipr file. The subprojects will only be mapped, if the Idea plugin has been
+     * The subprojects that should be mapped to modules in the ipr file. The subprojects will only be mapped if the Idea plugin has been
      * applied to them.
      */
-    Set subprojects
+    Set<Project> subprojects
 
     /**
      * The java version used for defining the project sdk.
@@ -40,7 +40,7 @@ public class IdeaProject extends XmlGeneratorTask<Project> {
     String javaVersion
 
     /**
-     * The wildcard resource patterns. Must not be null.
+     * The wildcard resource patterns.
      */
     @Input
     Set wildcards
diff --git a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/model/Jdk.groovy b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/model/Jdk.groovy
index 1e26451..20de840 100644
--- a/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/model/Jdk.groovy
+++ b/subprojects/gradle-idea/src/main/groovy/org/gradle/plugins/idea/model/Jdk.groovy
@@ -38,7 +38,7 @@ class Jdk {
             jdk15 = true
             languageLevel = 'JDK_1_5'
         }
-        else if (javaVersion.compareTo("1.6") >= 0) {
+        else if (javaVersion >= '1.6') {
             assertKeyword = true
             jdk15 = true
             languageLevel = 'JDK_1_6'
diff --git a/subprojects/gradle-jetty/jetty.gradle b/subprojects/gradle-jetty/jetty.gradle
index d48c65f..6b72d0c 100644
--- a/subprojects/gradle-jetty/jetty.gradle
+++ b/subprojects/gradle-jetty/jetty.gradle
@@ -27,7 +27,8 @@ dependencies {
             "org.mortbay.jetty:jsp-2.1:6.1.14 at jar",
             "org.eclipse.jdt:core:3.1.1 at jar",
             "org.mortbay.jetty:jetty-naming:6.1.25 at jar",
-            "org.mortbay.jetty:jetty-annotations:6.1.25 at jar"
+            "org.mortbay.jetty:jetty-annotations:6.1.25 at jar",
+            "org.apache.geronimo.specs:geronimo-annotation_1.0_spec:1.0 at jar"
 
     testCompile project(path: ':core', configuration: 'testFixtures')
     testRuntime project(path: ':core', configuration: 'testFixturesRuntime')
diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java
index 6c15bc9..304d52b 100644
--- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java
+++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java
@@ -411,6 +411,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.scanIntervalSeconds = scanIntervalSeconds;
     }
 
+    /**
+     * Returns the context path to use to deploy the web application.
+     */
     public String getContextPath() {
         return contextPath;
     }
@@ -435,6 +438,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.reload = reload;
     }
 
+    /**
+     * Returns the jetty configuration file to use. When {@code null}, no configuration file is used.
+     */
     @InputFile
     @Optional
     public File getJettyConfig() {
@@ -445,6 +451,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.jettyConfig = jettyConfig;
     }
 
+    /**
+     * Returns the TCP port for Jetty to listen on for stop requests.
+     */
     public Integer getStopPort() {
         return stopPort;
     }
@@ -453,6 +462,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.stopPort = stopPort;
     }
 
+    /**
+     * Returns the key to use to stop Jetty.
+     */
     public String getStopKey() {
         return stopKey;
     }
@@ -461,6 +473,10 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.stopKey = stopKey;
     }
 
+    /**
+     * Specifies whether the Jetty server should run in the background. When {@code true}, this task completes as
+     * soon as the server has started. When {@code false}, this task blocks until the Jetty server is stopped.
+     */
     public boolean isDaemon() {
         return daemon;
     }
@@ -469,6 +485,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.daemon = daemon;
     }
 
+    /**
+     * Returns the TCP port for Jetty to listen on for incoming HTTP requests.
+     */
     public Integer getHttpPort() {
         return httpPort;
     }
@@ -501,6 +520,9 @@ public abstract class AbstractJettyRunTask extends ConventionTask {
         this.requestLog = requestLog;
     }
 
+    /**
+     * Returns the classpath to make available to the web application.
+     */
     @InputFiles
     public Iterable<File> getAdditionalRuntimeJars() {
         return additionalRuntimeJars;
diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyPluginConvention.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyPluginConvention.java
index bff4f35..749b340 100644
--- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyPluginConvention.java
+++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyPluginConvention.java
@@ -25,6 +25,9 @@ public class JettyPluginConvention {
     private String stopKey;
     private Integer httpPort = 8080;
 
+    /**
+     * Returns the TCP port for Jetty to listen on for incoming HTTP requests.
+     */
     public Integer getHttpPort() {
         return httpPort;
     }
@@ -33,6 +36,9 @@ public class JettyPluginConvention {
         this.httpPort = httpPort;
     }
 
+    /**
+     * Returns the TCP port for Jetty to listen on for stop requests.
+     */
     public Integer getStopPort() {
         return stopPort;
     }
@@ -41,6 +47,9 @@ public class JettyPluginConvention {
         this.stopPort = stopPort;
     }
 
+    /**
+     * Returns the key to use to stop Jetty.
+     */
     public String getStopKey() {
         return stopKey;
     }
diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRun.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRun.java
index d896b15..13319a1 100644
--- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRun.java
+++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRun.java
@@ -39,7 +39,10 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
 
 /**
  * <p>Deploys an exploded web application to an embedded Jetty web container. Does not require that the web application
@@ -365,8 +368,9 @@ public class JettyRun extends AbstractJettyRunTask {
         this.jettyEnvXml = jettyEnvXml;
     }
 
-//    @InputFile @Optional
-
+    /**
+     * Returns the {@code web.xml} file to use. When {@code null}, no {@code web.xml} file is used.
+     */
     public File getWebXml() {
         return webXml;
     }
@@ -375,6 +379,9 @@ public class JettyRun extends AbstractJettyRunTask {
         this.webXml = webXml;
     }
 
+    /**
+     * Returns the directory containing the web application source files.
+     */
     @InputDirectory
     public File getWebAppSourceDirectory() {
         return webAppSourceDirectory;
diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRunWar.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRunWar.java
index e75d793..6a21177 100644
--- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRunWar.java
+++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyRunWar.java
@@ -102,6 +102,9 @@ public class JettyRunWar extends AbstractJettyRunTask {
     public void finishConfigurationBeforeStart() {
     }
 
+    /**
+     * Returns the web application to deploy.
+     */
     @InputFile
     public File getWebApp() {
         return webApp;
diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyStop.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyStop.java
index b340add..d47d678 100644
--- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyStop.java
+++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/JettyStop.java
@@ -28,7 +28,7 @@ import java.net.InetAddress;
 import java.net.Socket;
 
 /**
- * Stops the embedded Jetty web container.
+ * Stops the embedded Jetty web container, if it is running.
  */
 public class JettyStop extends ConventionTask {
     private static Logger logger = LoggerFactory.getLogger(JettyStop.class);
@@ -62,21 +62,21 @@ public class JettyStop extends ConventionTask {
     }
 
     /**
-     * Returns port to listen to stop jetty on sending stop command.
+     * Returns the TCP port to use to send stop command.
      */
     public Integer getStopPort() {
         return stopPort;
     }
 
     /**
-     * Sets port to listen to stop jetty on sending stop command.
+     * Sets the TCP port to use to send stop command.
      */
     public void setStopPort(Integer stopPort) {
         this.stopPort = stopPort;
     }
 
     /**
-     * Returns stop key.
+     * Returns the stop key.
      *
      * @see #setStopKey(String)
      */
diff --git a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonConnector.java b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonConnector.java
index d962a9d..bc36c87 100644
--- a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonConnector.java
+++ b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonConnector.java
@@ -57,29 +57,37 @@ public class DaemonConnector {
      * @return The connection, or null if not running.
      */
     Connection<Object> maybeConnect() {
+        URI uri = loadDaemonAddress();
+        if (uri == null) {
+            return null;
+        }
         try {
-            URI uri;
-            try {
-                FileInputStream inputStream = new FileInputStream(getRegistryFile());
-                try {
-                    // Acquire shared lock on file while reading it
-                    inputStream.getChannel().lock(0, Long.MAX_VALUE, true);
-                    DataInputStream dataInputStream = new DataInputStream(inputStream);
-                    uri = new URI(dataInputStream.readUTF());
-                } finally {
-                    // Also releases the lock
-                    inputStream.close();
-                }
-            } catch (FileNotFoundException e) {
-                // Ignore
-                return null;
-            }
+            return new TcpOutgoingConnector(getClass().getClassLoader()).connect(uri);
+        } catch (ConnectException e) {
+            // Ignore
+            return null;
+        }
+    }
+
+    private URI loadDaemonAddress() {
+        try {
+            FileInputStream inputStream = new FileInputStream(getRegistryFile());
             try {
-                return new TcpOutgoingConnector(getClass().getClassLoader()).connect(uri);
-            } catch (ConnectException e) {
-                // Ignore
-                return null;
+                // Acquire shared lock on file while reading it
+                inputStream.getChannel().lock(0, Long.MAX_VALUE, true);
+                DataInputStream dataInputStream = new DataInputStream(inputStream);
+                return new URI(dataInputStream.readUTF());
+            } finally {
+                // Also releases the lock
+                inputStream.close();
             }
+        } catch (FileNotFoundException e) {
+            // Ignore
+            return null;
+        } catch (EOFException e) {
+            // Daemon has created empty file, but not yet locked it or written anything to it.
+            // Or has crashed while writing the registry file.
+            return null;
         } catch (Exception e) {
             throw UncheckedException.asUncheckedException(e);
         }
@@ -97,41 +105,45 @@ public class DaemonConnector {
         }
 
         LOGGER.info("Starting Gradle daemon");
-        try {
-            startDaemon();
-            Date expiry = new Date(System.currentTimeMillis() + 30000L);
-            do {
-                connection = maybeConnect();
-                if (connection != null) {
-                    return connection;
-                }
+        startDaemon();
+        Date expiry = new Date(System.currentTimeMillis() + 30000L);
+        do {
+            connection = maybeConnect();
+            if (connection != null) {
+                return connection;
+            }
+            try {
                 Thread.sleep(200L);
-            } while (System.currentTimeMillis() < expiry.getTime());
-        } catch (Exception e) {
-            throw UncheckedException.asUncheckedException(e);
-        }
+            } catch (InterruptedException e) {
+                throw UncheckedException.asUncheckedException(e);
+            }
+        } while (System.currentTimeMillis() < expiry.getTime());
 
         throw new GradleException("Timeout waiting to connect to Gradle daemon.");
     }
 
-    private void startDaemon() throws IOException {
-        List<String> daemonArgs = new ArrayList<String>();
-        daemonArgs.add(Jvm.current().getJavaExecutable().getAbsolutePath());
-        daemonArgs.add("-Xmx1024m");
-        daemonArgs.add("-XX:MaxPermSize=256m");
-        daemonArgs.add("-cp");
-        daemonArgs.add(GUtil.join(new DefaultClassPathRegistry().getClassPathFiles("GRADLE_RUNTIME"),
-                File.pathSeparator));
-        daemonArgs.add(GradleDaemon.class.getName());
-        daemonArgs.add(String.format("-%s", DefaultCommandLineConverter.GRADLE_USER_HOME));
-        daemonArgs.add(userHomeDir.getAbsolutePath());
-        ProcessBuilder builder = new ProcessBuilder(daemonArgs);
-        builder.directory(userHomeDir);
-        userHomeDir.mkdirs();
-        Process process = builder.start();
-        process.getOutputStream().close();
-        process.getErrorStream().close();
-        process.getInputStream().close();
+    private void startDaemon() {
+        try {
+            List<String> daemonArgs = new ArrayList<String>();
+            daemonArgs.add(Jvm.current().getJavaExecutable().getAbsolutePath());
+            daemonArgs.add("-Xmx1024m");
+            daemonArgs.add("-XX:MaxPermSize=256m");
+            daemonArgs.add("-cp");
+            daemonArgs.add(GUtil.join(new DefaultClassPathRegistry().getClassPathFiles("GRADLE_RUNTIME"),
+                    File.pathSeparator));
+            daemonArgs.add(GradleDaemon.class.getName());
+            daemonArgs.add(String.format("-%s", DefaultCommandLineConverter.GRADLE_USER_HOME));
+            daemonArgs.add(userHomeDir.getAbsolutePath());
+            ProcessBuilder builder = new ProcessBuilder(daemonArgs);
+            builder.directory(userHomeDir);
+            userHomeDir.mkdirs();
+            Process process = builder.start();
+            process.getOutputStream().close();
+            process.getErrorStream().close();
+            process.getInputStream().close();
+        } catch (IOException e) {
+            throw UncheckedException.asUncheckedException(e);
+        }
     }
 
     /**
@@ -145,7 +157,7 @@ public class DaemonConnector {
         final CompletionHandler finished = new CompletionHandler();
 
         LOGGER.lifecycle("Awaiting requests.");
-        
+
         URI uri = incomingConnector.accept(new Action<ConnectEvent<Connection<Object>>>() {
             public void execute(ConnectEvent<Connection<Object>> connectionConnectEvent) {
                 try {
@@ -158,10 +170,21 @@ public class DaemonConnector {
             }
         });
 
+        storeDaemonAddress(uri);
+
+        boolean stopped = finished.awaitStop();
+        if (!stopped) {
+            LOGGER.lifecycle("Time-out waiting for requests. Stopping.");
+        }
+        new CompositeStoppable(incomingConnector, executorFactory).stop();
+
+        getRegistryFile().delete();
+    }
+
+    private void storeDaemonAddress(URI uri) {
         try {
             File registryFile = getRegistryFile();
             registryFile.getParentFile().mkdirs();
-//            registryFile.createNewFile();
             FileOutputStream outputStream = new FileOutputStream(registryFile);
             try {
                 // Lock file while writing to it
@@ -176,14 +199,6 @@ public class DaemonConnector {
         } catch (IOException e) {
             throw UncheckedException.asUncheckedException(e);
         }
-
-        boolean stopped = finished.awaitStop();
-        if (!stopped) {
-            LOGGER.lifecycle("Time-out waiting for requests. Stopping.");
-        }
-        new CompositeStoppable(incomingConnector, executorFactory).stop();
-
-        getRegistryFile().delete();
     }
 
     private File getRegistryFile() {
@@ -199,11 +214,12 @@ public class DaemonConnector {
         private long expiry;
 
         CompletionHandler() {
-            onActivityComplete();
+            resetTimer();
         }
 
         /**
          * Waits until stopped, or timeout.
+         *
          * @return true if stopped, false if timeout
          */
         public boolean awaitStop() {
@@ -211,7 +227,11 @@ public class DaemonConnector {
             try {
                 while (running || (!stopped && System.currentTimeMillis() < expiry)) {
                     try {
-                        condition.awaitUntil(new Date(expiry));
+                        if (running) {
+                            condition.await();
+                        } else {
+                            condition.awaitUntil(new Date(expiry));
+                        }
                     } catch (InterruptedException e) {
                         throw UncheckedException.asUncheckedException(e);
                     }
@@ -247,12 +267,17 @@ public class DaemonConnector {
         public void onActivityComplete() {
             lock.lock();
             try {
+                assert running;
                 running = false;
-                expiry = System.currentTimeMillis() + THREE_HOURS;
+                resetTimer();
                 condition.signalAll();
             } finally {
                 lock.unlock();
             }
         }
+
+        private void resetTimer() {
+            expiry = System.currentTimeMillis() + THREE_HOURS;
+        }
     }
 }
\ No newline at end of file
diff --git a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonMain.java b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonMain.java
index 1d62ff0..c1b0a23 100644
--- a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonMain.java
+++ b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/DaemonMain.java
@@ -16,6 +16,7 @@
 package org.gradle.launcher;
 
 import org.gradle.BuildExceptionReporter;
+import org.gradle.api.logging.StandardOutputListener;
 import org.gradle.initialization.DefaultBuildRequestMetaData;
 import org.gradle.initialization.GradleLauncherFactory;
 import org.gradle.StartParameter;
@@ -36,7 +37,10 @@ import org.gradle.logging.internal.OutputEvent;
 import org.gradle.logging.internal.OutputEventListener;
 import org.gradle.messaging.concurrent.Stoppable;
 import org.gradle.messaging.remote.internal.Connection;
+import org.gradle.util.GradleVersion;
+import org.gradle.util.UncheckedException;
 
+import java.io.*;
 import java.util.Arrays;
 import java.util.Properties;
 
@@ -56,10 +60,28 @@ public class DaemonMain implements Runnable {
         launcherFactory = new DefaultGradleLauncherFactory(loggingServices);
     }
 
-    public static void main(String[] args) {
+    public static void main(String[] args) throws IOException {
         StartParameter startParameter = new DefaultCommandLineConverter().convert(Arrays.asList(args));
         DaemonConnector connector = new DaemonConnector(startParameter.getGradleUserHomeDir());
-        new DaemonMain(new LoggingServiceRegistry(), connector).run();
+        LoggingServiceRegistry loggingServices = new LoggingServiceRegistry();
+        addLogFileWriters(startParameter, loggingServices);
+        new DaemonMain(loggingServices, connector).run();
+    }
+
+    private static void addLogFileWriters(StartParameter startParameter, LoggingServiceRegistry loggingServices) throws IOException {
+        File stderrOut = new File(startParameter.getGradleUserHomeDir(), String.format("daemon/%s/daemon.err.log", new GradleVersion().getVersion()));
+        stderrOut.getParentFile().mkdirs();
+        final Writer writer = new BufferedWriter(new FileWriter(stderrOut));
+        loggingServices.get(LoggingOutputInternal.class).addStandardErrorListener(new StandardOutputListener() {
+            public void onOutput(CharSequence output) {
+                try {
+                    writer.append(output);
+                    writer.flush();
+                } catch (IOException e) {
+                    throw UncheckedException.asUncheckedException(e);
+                }
+            }
+        });
     }
 
     public void run() {
diff --git a/subprojects/gradle-maven/src/main/groovy/org/gradle/api/plugins/MavenPluginConvention.java b/subprojects/gradle-maven/src/main/groovy/org/gradle/api/plugins/MavenPluginConvention.java
index 8e4fabd..1488f26 100644
--- a/subprojects/gradle-maven/src/main/groovy/org/gradle/api/plugins/MavenPluginConvention.java
+++ b/subprojects/gradle-maven/src/main/groovy/org/gradle/api/plugins/MavenPluginConvention.java
@@ -41,14 +41,25 @@ public class MavenPluginConvention {
         this.project = project;
     }
 
+    /**
+     * Returns the name of the directory to generate Maven POMs into, relative to the build directory.
+     */
     public String getPomDirName() {
         return pomDirName;
     }
 
+    /**
+     * Sets the name of the directory to generate Maven POMs into, relative to the build directory.
+     */
     public void setPomDirName(String pomDirName) {
         this.pomDirName = pomDirName;
     }
 
+    /**
+     * Returns the set of rules for how to map Gradle dependencies to Maven scopes.
+     *
+     * @return The mapping rules.
+     */
     public Conf2ScopeMappingContainer getConf2ScopeMappings() {
         return conf2ScopeMappings;
     }
@@ -57,19 +68,33 @@ public class MavenPluginConvention {
         this.conf2ScopeMappings = conf2ScopeMappings;
     }
 
+    /**
+     * Returns the directory to generate Maven POMs into.
+     */
     public File getPomDir() {
         return project.getFileResolver().withBaseDir(project.getBuildDir()).resolve(pomDirName);
     }
 
+    /**
+     * Creates a new {@link MavenPom}.
+     *
+     * @return The POM instance.
+     */
     public MavenPom pom() {
         return pom(null);
     }
 
+    /**
+     * Creates and configures a new {@link MavenPom}. The given closure is executed to configure the new POM instance.
+     *
+     * @param configureClosure The closure to use to configure the POM instance.
+     * @return The POM instance.
+     */
     public MavenPom pom(Closure configureClosure) {
         DefaultMavenPom pom = new DefaultMavenPom(project.getConfigurations(),
                 new DefaultConf2ScopeMappingContainer(conf2ScopeMappings.getMappings()),
                 new DefaultPomDependenciesConverter(new DefaultExcludeRuleConverter()),
-                ((ProjectInternal) project).getFileResolver());
+                project.getFileResolver());
         pom.setGroupId(project.getGroup().toString());
         pom.setArtifactId(project.getName());
         pom.setVersion(project.getVersion().toString());
diff --git a/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy b/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
index d03625f..794b0a8 100644
--- a/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
+++ b/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 the original author or authors.
+ * Copyright 2010 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.
@@ -36,41 +36,44 @@ class CrossVersionCompatibilityIntegrationTest {
 
     private final BasicGradleDistribution gradle09rc1 = dist.previousVersion('0.9-rc-1')
     private final BasicGradleDistribution gradle09rc2 = dist.previousVersion('0.9-rc-2')
+    private final BasicGradleDistribution gradle09rc3 = dist.previousVersion('0.9-rc-3')
 
     @Test
     public void canUseOpenApiFromCurrentVersionToBuildUsingAnOlderVersion() {
-        [gradle09rc1, gradle09rc2].each {
+        [gradle09rc1, gradle09rc2, gradle09rc3].each {
             checkCanBuildUsing(dist, it)
         }
     }
 
     @Test
     public void canUseOpenApiFromOlderVersionToBuildUsingCurrentVersion() {
-        [gradle09rc1, gradle09rc2].each {
+        [gradle09rc1, gradle09rc2, gradle09rc3].each {
             checkCanBuildUsing(it, dist)
         }
     }
 
     def checkCanBuildUsing(BasicGradleDistribution openApiVersion, BasicGradleDistribution buildVersion) {
-        if (!buildVersion.worksWith(Jvm.current())) {
-            System.out.println("skipping $buildVersion as it does not work with ${Jvm.current()}.")
-            return
+        try {
+            if (!buildVersion.worksWith(Jvm.current())) {
+                System.out.println("skipping $buildVersion as it does not work with ${Jvm.current()}.")
+                return
+            }
+            if (!openApiVersion.worksWith(Jvm.current())) {
+                System.out.println("skipping $openApiVersion as it does not work with ${Jvm.current()}.")
+                return
+            }
+            def testClasses = AbstractClassPathProvider.getClasspathForClass(CrossVersionBuilder.class)
+            def junitJar = AbstractClassPathProvider.getClasspathForClass(Assert.class)
+            def classpath = [testClasses, junitJar] + openApiVersion.gradleHomeDir.file('lib').listFiles().findAll { it.name =~ /gradle-open-api.*\.jar/ }
+            logger.info('Using Open API classpath {}', classpath)
+            def classloader = new URLClassLoader(classpath.collect { it.toURI().toURL() } as URL[], ClassLoader.systemClassLoader.parent)
+            def builder = classloader.loadClass(CrossVersionBuilder.class.name).newInstance()
+            builder.targetGradleHomeDir = buildVersion.gradleHomeDir
+            builder.currentDir = dist.testDir
+            builder.version = buildVersion.version
+            builder.build()
+        } catch (Throwable throwable) {
+            throw new RuntimeException("Failed to build using $buildVersion via the open API of $openApiVersion", throwable)
         }
-        if (!openApiVersion.worksWith(Jvm.current())) {
-            System.out.println("skipping $openApiVersion as it does not work with ${Jvm.current()}.")
-            return
-        }
-
-        def testClasses = AbstractClassPathProvider.getClasspathForClass(CrossVersionBuilder.class)
-        def junitJar = AbstractClassPathProvider.getClasspathForClass(Assert.class)
-        def classpath = [testClasses, junitJar] + openApiVersion.gradleHomeDir.file('lib').listFiles().findAll { it.name =~ /gradle-open-api.*\.jar/ }
-        logger.info('Using Open API classpath {}', classpath)
-        def classloader = new URLClassLoader(classpath.collect { it.toURI().toURL() } as URL[], ClassLoader.systemClassLoader.parent)
-
-        def builder = classloader.loadClass(CrossVersionBuilder.class.name).newInstance()
-        builder.targetGradleHomeDir = buildVersion.gradleHomeDir
-        builder.currentDir = dist.testDir
-        builder.version = buildVersion.version
-        builder.build()
     }
 }
diff --git a/subprojects/gradle-osgi/src/main/groovy/org/gradle/api/plugins/osgi/OsgiPluginConvention.java b/subprojects/gradle-osgi/src/main/groovy/org/gradle/api/plugins/osgi/OsgiPluginConvention.java
index 71b683e..d36e1ad 100644
--- a/subprojects/gradle-osgi/src/main/groovy/org/gradle/api/plugins/osgi/OsgiPluginConvention.java
+++ b/subprojects/gradle-osgi/src/main/groovy/org/gradle/api/plugins/osgi/OsgiPluginConvention.java
@@ -36,13 +36,12 @@ public class OsgiPluginConvention {
     }
 
     /**
-     * Returns a new instance of {@link org.gradle.api.plugins.osgi.OsgiManifest}. The returned object is preconfigured with:
-     * <blockquote>
+     * Creates a new instance of {@link org.gradle.api.plugins.osgi.OsgiManifest}. The returned object is preconfigured with:
      * <pre>
      * version: project.version
      * name: project.archivesBaseName
      * symbolicName: project.group + "." + project.archivesBaseName (see below for exceptions to this rule)
-     * </pre></blockquote>
+     * </pre>
      *
      * The symbolic name is usually the group + "." + archivesBaseName, with the following exceptions
      * <ul>
@@ -60,7 +59,7 @@ public class OsgiPluginConvention {
     }
 
     /**
-     * Returns a new instance of an  {@link org.gradle.api.plugins.osgi.OsgiManifest} . The closure configures
+     * Creates and configures a new instance of an  {@link org.gradle.api.plugins.osgi.OsgiManifest} . The closure configures
      * the new manifest instance before it is returned.
      */
     public OsgiManifest osgiManifest(Closure closure) {
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
index 8beff82..efe0225 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassExecuter.java
@@ -16,10 +16,7 @@
 
 package org.gradle.api.internal.tasks.testing.junit;
 
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.framework.TestListener;
-import junit.framework.TestResult;
+import junit.framework.*;
 import org.gradle.api.internal.tasks.testing.*;
 import org.gradle.util.IdGenerator;
 import org.gradle.util.TimeProvider;
@@ -75,6 +72,10 @@ public class JUnitTestClassExecuter {
                     Description.createSuiteDescription(String.format("initializationError(%s)", testClassName)), e);
         }
 
+        if (TestCase.class.isAssignableFrom(testClass)) {
+            // Use a TestSuite directly, so that we get access to the test object in JUnitTestResultProcessorAdapter
+            return new TestSuite(testClass.asSubclass(TestCase.class));
+        }
         return new JUnit4TestAdapter(testClass);
     }
 
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestResultProcessorAdapter.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestResultProcessorAdapter.java
index 3b1990f..c3af152 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestResultProcessorAdapter.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestResultProcessorAdapter.java
@@ -47,7 +47,7 @@ public class JUnitTestResultProcessorAdapter implements TestListener {
     private void doStartTest(Test test, TestDescriptorInternal descriptor) {
         synchronized (lock) {
             TestDescriptorInternal oldTest = executing.put(test, descriptor);
-            assert oldTest == null;
+            assert oldTest == null : String.format("Unexpected start event for test '%s' (class %s)", test, test.getClass());
         }
         long startTime = timeProvider.getCurrentTime();
         resultProcessor.started(descriptor, new TestStartEvent(startTime));
@@ -77,7 +77,7 @@ public class JUnitTestResultProcessorAdapter implements TestListener {
             TestSetup testSetup = (TestSetup) test;
             return new DefaultTestDescriptor(idGenerator.generateId(), testSetup.getClass().getName(), "classMethod");
         }
-        assert test instanceof TestSuite : String.format("Should be TestSuite, is " + test.getClass());
+        assert test instanceof TestSuite : String.format("Unexpected type for test '%s'. Should be TestSuite, is %s", test, test.getClass());
         TestSuite suite = (TestSuite) test;
         return new DefaultTestMethodDescriptor(idGenerator.generateId(), suite.getName(), "classMethod");
     }
@@ -91,7 +91,7 @@ public class JUnitTestResultProcessorAdapter implements TestListener {
         TestDescriptorInternal testInternal;
         synchronized (lock) {
             testInternal = executing.remove(test);
-            assert testInternal != null;
+            assert testInternal != null : String.format("Unexpected end event for test '%s' (class %s)", test, test.getClass());
         }
         resultProcessor.completed(testInternal.getId(), new TestCompleteEvent(endTime));
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitXmlReportGenerator.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitXmlReportGenerator.java
index 32501c1..4e0ae23 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitXmlReportGenerator.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitXmlReportGenerator.java
@@ -94,22 +94,22 @@ public class JUnitXmlReportGenerator extends StateTrackingTestResultProcessor {
                     DateUtils.ISO8601_DATETIME_PATTERN));
             rootElement.setAttribute(XMLConstants.HOSTNAME, hostName);
             Element stdoutElement = testSuiteReport.createElement(XMLConstants.SYSTEM_OUT);
-            stdoutElement.appendChild(testSuiteReport.createCDATASection(outputs.get(
-                    TestOutputEvent.Destination.StdOut).toString()));
+            stdoutElement.appendChild(testSuiteReport.createCDATASection(outputs.get(TestOutputEvent.Destination.StdOut)
+                    .toString()));
             rootElement.appendChild(stdoutElement);
             Element stderrElement = testSuiteReport.createElement(XMLConstants.SYSTEM_ERR);
-            stderrElement.appendChild(testSuiteReport.createCDATASection(outputs.get(
-                    TestOutputEvent.Destination.StdErr).toString()));
+            stderrElement.appendChild(testSuiteReport.createCDATASection(outputs.get(TestOutputEvent.Destination.StdErr)
+                    .toString()));
             rootElement.appendChild(stderrElement);
         }
 
         element.setAttribute(XMLConstants.ATTR_TIME, String.valueOf(state.getExecutionTime() / 1000.0));
-        if (state.failure != null) {
-            Element failure = testSuiteReport.createElement(XMLConstants.FAILURE);
-            element.appendChild(failure);
-            failure.setAttribute(XMLConstants.ATTR_MESSAGE, failureMessage(state));
-            failure.setAttribute(XMLConstants.ATTR_TYPE, state.failure.getClass().getName());
-            failure.appendChild(testSuiteReport.createTextNode(stackTrace(state)));
+        for (Throwable failure : state.failures) {
+            Element failureElement = testSuiteReport.createElement(XMLConstants.FAILURE);
+            element.appendChild(failureElement);
+            failureElement.setAttribute(XMLConstants.ATTR_MESSAGE, failureMessage(failure));
+            failureElement.setAttribute(XMLConstants.ATTR_TYPE, failure.getClass().getName());
+            failureElement.appendChild(testSuiteReport.createTextNode(stackTrace(failure)));
         }
 
         if (state.equals(testSuite)) {
@@ -130,11 +130,11 @@ public class JUnitXmlReportGenerator extends StateTrackingTestResultProcessor {
         }
     }
 
-    private String stackTrace(TestState state) {
+    private String stackTrace(Throwable throwable) {
         try {
             StringWriter stringWriter = new StringWriter();
             PrintWriter writer = new PrintWriter(stringWriter);
-            state.failure.printStackTrace(writer);
+            throwable.printStackTrace(writer);
             writer.close();
             return stringWriter.toString();
         } catch (Throwable t) {
@@ -146,12 +146,12 @@ public class JUnitXmlReportGenerator extends StateTrackingTestResultProcessor {
         }
     }
 
-    private String failureMessage(TestState state) {
+    private String failureMessage(Throwable throwable) {
         try {
-            return state.failure.toString();
+            return throwable.toString();
         } catch (Throwable t) {
             return String.format("Could not determine failure message for exception of type %s: %s",
-                    state.failure.getClass().getName(), t);
+                    throwable.getClass().getName(), t);
         }
     }
 
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/DefaultTestResult.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/DefaultTestResult.java
index b4abc9d..d72e78c 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/DefaultTestResult.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/DefaultTestResult.java
@@ -19,9 +19,10 @@ package org.gradle.api.internal.tasks.testing.results;
 import org.gradle.api.tasks.testing.TestResult;
 
 import java.io.Serializable;
+import java.util.List;
 
 public class DefaultTestResult implements TestResult, Serializable {
-    private final Throwable error;
+    private final List<Throwable> failures;
     private final ResultType result;
     private final long startTime;
     private final long endTime;
@@ -29,8 +30,8 @@ public class DefaultTestResult implements TestResult, Serializable {
     private final long successfulCount;
     private final long failedCount;
 
-    public DefaultTestResult(ResultType result, Throwable error, long startTime, long endTime, long testCount, long successfulCount, long failedCount) {
-        this.error = error;
+    public DefaultTestResult(ResultType result, List<Throwable> failures, long startTime, long endTime, long testCount, long successfulCount, long failedCount) {
+        this.failures = failures;
         this.result = result;
         this.startTime = startTime;
         this.endTime = endTime;
@@ -44,10 +45,11 @@ public class DefaultTestResult implements TestResult, Serializable {
     }
 
     public Throwable getException() {
-        if (result != ResultType.FAILURE) {
-            throw new IllegalStateException("No exception to return");
-        }
-        return error;
+        return failures.isEmpty() ? null : failures.get(0);
+    }
+
+    public List<Throwable> getExceptions() {
+        return failures;
     }
 
     public long getStartTime() {
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/StateTrackingTestResultProcessor.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/StateTrackingTestResultProcessor.java
index 744c3d4..efea308 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/StateTrackingTestResultProcessor.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/StateTrackingTestResultProcessor.java
@@ -19,7 +19,9 @@ package org.gradle.api.internal.tasks.testing.results;
 import org.gradle.api.internal.tasks.testing.*;
 import org.gradle.api.tasks.testing.TestResult;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public abstract class StateTrackingTestResultProcessor implements TestResultProcessor {
@@ -57,7 +59,7 @@ public abstract class StateTrackingTestResultProcessor implements TestResultProc
             throw new IllegalArgumentException(String.format("Received a failure event for test with unknown id '%s'.",
                     testId));
         }
-        testState.failure = result;
+        testState.failures.add(result);
     }
 
     public void output(Object testId, TestOutputEvent event) {
@@ -74,7 +76,7 @@ public abstract class StateTrackingTestResultProcessor implements TestResultProc
         public final TestDescriptorInternal test;
         final TestStartEvent startEvent;
         public boolean failedChild;
-        public Throwable failure;
+        public List<Throwable> failures = new ArrayList<Throwable>();
         public long testCount;
         public long successfulCount;
         public long failedCount;
@@ -87,7 +89,7 @@ public abstract class StateTrackingTestResultProcessor implements TestResultProc
         }
 
         public boolean isFailed() {
-            return failedChild || failure != null;
+            return failedChild || !failures.isEmpty();
         }
 
         public long getStartTime() {
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapter.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapter.java
index 9fe2959..8821e93 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapter.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapter.java
@@ -39,7 +39,7 @@ public class TestListenerAdapter extends StateTrackingTestResultProcessor {
 
     @Override
     protected void completed(TestState state) {
-        TestResult result = new DefaultTestResult(state.resultType, state.failure, state.getStartTime(),
+        TestResult result = new DefaultTestResult(state.resultType, state.failures, state.getStartTime(),
                 state.getEndTime(), state.testCount, state.successfulCount, state.failedCount);
         TestDescriptorInternal test = state.test;
         if (test.isComposite()) {
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePlugin.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePlugin.groovy
index 854cb85..f2f700a 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePlugin.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePlugin.groovy
@@ -134,7 +134,7 @@ class BasePlugin implements Plugin<Project> {
                 apply: {String taskName ->
                     Set<Configuration> configurations = project.configurations.all
                     for (Configuration configuration: configurations) {
-                        if (taskName.equals(configuration.uploadTaskName)) {
+                        if (taskName == configuration.uploadTaskName) {
                             createUploadTask(configuration.uploadTaskName, configuration, project)
                         }
                     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePluginConvention.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePluginConvention.groovy
index 43c0037..2c273b6 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePluginConvention.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/BasePluginConvention.groovy
@@ -21,8 +21,19 @@ import org.gradle.api.internal.project.ProjectInternal
 public class BasePluginConvention {
     ProjectInternal project
 
+    /**
+     * The name for the distributions directory. This in interpreted relative to the project' build directory.
+     */
     String distsDirName
+
+    /**
+     * The name for the libs directory. This in interpreted relative to the project' build directory.
+     */
     String libsDirName
+
+    /**
+     * The base name to use for archive files.
+     */
     String archivesBaseName
 
     BasePluginConvention(Project project) {
@@ -32,10 +43,20 @@ public class BasePluginConvention {
         libsDirName = 'libs'
     }
 
+    /**
+     * Returns the directory to generate TAR and ZIP archives into.
+     *
+     * @return The directory. Never returns null.
+     */
     File getDistsDir() {
         project.fileResolver.withBaseDir(project.buildDir).resolve(distsDirName)
     }
 
+    /**
+     * Returns the directory to generate JAR and WAR archives into.
+     *
+     * @return The directory. Never returns null.
+     */
     File getLibsDir() {
         project.fileResolver.withBaseDir(project.buildDir).resolve(libsDirName)
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/JavaPluginConvention.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/JavaPluginConvention.groovy
index ad794fc..8531fe4 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/JavaPluginConvention.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/JavaPluginConvention.groovy
@@ -26,8 +26,8 @@ import org.gradle.api.tasks.SourceSetContainer
 import org.gradle.util.ConfigureUtil
 
 /**
- * Is mixed in into the project when applying the {@org.gradle.api.plugins.JavaBasePlugin} or the
- * {@org.gradle.api.plugins.JavaPlugin}.
+ * Is mixed in into the project when applying the {@link org.gradle.api.plugins.JavaBasePlugin} or the
+ * {@link org.gradle.api.plugins.JavaPlugin}.
  *
  * @author Hans Dockter
  */
@@ -77,6 +77,14 @@ class JavaPluginConvention {
         metaInf = []
     }
 
+    /**
+     * Configures the source sets of this project.
+     *
+     * <p>The given closure is executed to configure the {@link SourceSetContainer}. The {@link SourceSetContainer}
+     * is passed to the closure as its delegate.
+     *
+     * @param closure The closure to execute.
+     */
     def sourceSets(Closure closure) {
         sourceSets.configure(closure)
     }
@@ -114,13 +122,13 @@ class JavaPluginConvention {
      * Returns the source compatibility used for compiling Java sources.
      */
     JavaVersion getSourceCompatibility() {
-            srcCompat ?: JavaVersion.VERSION_1_5
+        srcCompat ?: JavaVersion.VERSION_1_5
     }
 
     /**
      * Sets the source compatibility used for compiling Java sources.
      *
-     * @value The value for the source compatibilty as defined by   {@link JavaVersion#toVersion(Object)}
+     * @value The value for the source compatibility as defined by {@link JavaVersion#toVersion(Object)}
      */
     void setSourceCompatibility(def value) {
         srcCompat = JavaVersion.toVersion(value)
@@ -130,7 +138,7 @@ class JavaPluginConvention {
      * Returns the target compatibility used for compiling Java sources.
      */
     JavaVersion getTargetCompatibility() {
-            targetCompat ?: sourceCompatibility
+        targetCompat ?: sourceCompatibility
     }
 
     /**
@@ -143,15 +151,17 @@ class JavaPluginConvention {
     }
 
     /**
-     * Returns a new instance of an {@link Manifest}.
+     * Creates a new instance of a {@link Manifest}.
      */
     public Manifest manifest() {
         return manifest(null);
     }
 
     /**
-     * Returns a new instance of an {@link Manifest}. The closure configures
+     * Creates and configures a new instance of a {@link Manifest}. The given closure configures
      * the new manifest instance before it is returned.
+     *
+     * @param closure The closure to use to configure the manifest.
      */
     public Manifest manifest(Closure closure) {
         return ConfigureUtil.configure(closure, new DefaultManifest(((ProjectInternal) getProject()).fileResolver));
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/ProjectReportsPluginConvention.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/ProjectReportsPluginConvention.groovy
index 42aeb87..b46a6b5 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/ProjectReportsPluginConvention.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/ProjectReportsPluginConvention.groovy
@@ -19,13 +19,19 @@ import org.gradle.api.Project
 import org.gradle.util.WrapUtil
 
 public class ProjectReportsPluginConvention {
+    /**
+     * The name of the directory to generate the project reports into, relative to the project's reports dir.
+     */
     String projectReportDirName = 'project'
     private final Project project
 
     def ProjectReportsPluginConvention(Project project) {
         this.project = project;
     }
-    
+
+    /**
+     * Returns the directory to generate the project reports into.
+     */
     File getProjectReportDir() {
         new File(project.convention.getPlugin(ReportingBasePluginConvention).reportsDir, projectReportDirName)
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
index 2a4f998..a7057e0 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/plugins/WarPluginConvention.groovy
@@ -18,6 +18,9 @@ package org.gradle.api.plugins
 import org.gradle.api.Project
 
 public class WarPluginConvention {
+    /**
+     * The name of the web application directory, relative to the project directory.
+     */
     String webAppDirName
     final Project project
 
@@ -26,6 +29,9 @@ public class WarPluginConvention {
         webAppDirName = 'src/main/webapp'
     }
 
+    /**
+     * Returns the web application directory.
+     */
     File getWebAppDir() {
         project.file(webAppDirName)
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/GroovySourceSet.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/GroovySourceSet.java
index c93c9ed..7910e71 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/GroovySourceSet.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/GroovySourceSet.java
@@ -33,8 +33,9 @@ public interface GroovySourceSet {
     SourceDirectorySet getGroovy();
 
     /**
-     * Configures the Groovy source for this set. The given closure is used to configure the {@code SourceDirectorySet}
-     * which contains the Groovy source.
+     * Configures the Groovy source for this set.
+     *
+     * <p>The given closure is used to configure the {@link SourceDirectorySet} which contains the Groovy source.
      *
      * @param configureClosure The closure to use to configure the Groovy source.
      * @return this
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/SourceSet.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/SourceSet.java
index b18a2bc..701cffc 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/SourceSet.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/SourceSet.java
@@ -109,8 +109,9 @@ public interface SourceSet {
     SourceDirectorySet getResources();
 
     /**
-     * Configures the non-Java resources for this set. The given closure is used to configure the {@code
-     * SourceDirectorySet} which contains the resources.
+     * Configures the non-Java resources for this set.
+     *
+     * <p>The given closure is used to configure the {@link SourceDirectorySet} which contains the resources.
      *
      * @param configureClosure The closure to use to configure the resources.
      * @return this
@@ -125,8 +126,9 @@ public interface SourceSet {
     SourceDirectorySet getJava();
 
     /**
-     * Configures the Java source for this set. The given closure is used to configure the {@code SourceDirectorySet}
-     * which contains the Java source.
+     * Configures the Java source for this set.
+     *
+     * <p>The given closure is used to configure the {@link SourceDirectorySet} which contains the Java source.
      *
      * @param configureClosure The closure to use to configure the Java source.
      * @return this
@@ -134,8 +136,8 @@ public interface SourceSet {
     SourceSet java(Closure configureClosure);
 
     /**
-     * All Java source files for this source set. This includes, for example, source which is directly compiled, and source
-     * which is indirectly compiled through joint compilation.
+     * All Java source files for this source set. This includes, for example, source which is directly compiled, and
+     * source which is indirectly compiled through joint compilation.
      *
      * @return the Java source. Never returns null.
      */
@@ -182,7 +184,6 @@ public interface SourceSet {
      *
      * @param verb The action, may be null.
      * @param target The target, may be null
-     *
      * @return The task name, generally of the form ${verb}${name}${noun}
      */
     String getTaskName(String verb, String target);
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/Jar.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/Jar.groovy
index 77019f2..92c2065 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/Jar.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/Jar.groovy
@@ -22,6 +22,7 @@ import org.gradle.api.java.archives.internal.DefaultManifest
 import org.gradle.util.ConfigureUtil
 import org.gradle.api.internal.file.copy.CopySpecImpl
 import org.gradle.api.file.FileCopyDetails
+import org.gradle.api.java.archives.Manifest
 
 /**
  * Assembles a JAR archive.
@@ -31,7 +32,7 @@ import org.gradle.api.file.FileCopyDetails
 public class Jar extends Zip {
     public static final String DEFAULT_EXTENSION = 'jar'
 
-    private DefaultManifest manifest
+    private Manifest manifest
     private final CopySpecImpl metaInf
 
     Jar() {
@@ -42,7 +43,7 @@ public class Jar extends Zip {
         metaInf.addChild().from {
             MapFileTree manifestSource = new MapFileTree(temporaryDir)
             manifestSource.add('MANIFEST.MF') {OutputStream outstr ->
-                DefaultManifest manifest = getManifest() ?: new DefaultManifest(null)
+                Manifest manifest = getManifest() ?: new DefaultManifest(null)
                 manifest.writeTo(new OutputStreamWriter(outstr))
             }
             manifestSource
@@ -54,14 +55,32 @@ public class Jar extends Zip {
         }
     }
 
-    public DefaultManifest getManifest() {
+    /**
+     * Returns the manifest for this JAR archive.
+     * @return The manifest
+     */
+    public Manifest getManifest() {
         return manifest;
     }
 
-    public void setManifest(DefaultManifest manifest) {
+    /**
+     * Sets the manifest for this JAR archive.
+     *
+     * @param manifest The manifest. May be null.
+     */
+    public void setManifest(Manifest manifest) {
         this.manifest = manifest;
     }
 
+    /**
+     * Configures the manifest for this JAR archive.
+     *
+     * <p>The given closure is executed to configure the manifest. The {@link org.gradle.api.java.archives.Manifest}
+     * is passed to the closure as its delegate.</p>
+     *
+     * @param configureClosure The closure.
+     * @return This.
+     */
     public Jar manifest(Closure configureClosure) {
         if (getManifest() == null) {
             manifest = new DefaultManifest(project.fileResolver)
@@ -74,6 +93,15 @@ public class Jar extends Zip {
         return metaInf.addChild()
     }
 
+    /**
+     * Adds content to this JAR archive's META-INF directory.
+     *
+     * <p>The given closure is executed to configure a {@code CopySpec}. The {@link CopySpec} is passed to the closure
+     * as its delegate.</p>
+     *
+     * @param configureClosure The closure.
+     * @return The created {@code CopySpec}
+     */
     public CopySpec metaInf(Closure configureClosure) {
         return ConfigureUtil.configure(configureClosure, getMetaInf())
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/War.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/War.groovy
index ac93a1b..8e61d0d 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/War.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/bundling/War.groovy
@@ -26,7 +26,7 @@ import org.gradle.api.internal.file.copy.CopySpecImpl
 
 /**
  * Assembles a WAR archive.
- * 
+ *
  * @author Hans Dockter
  */
 class War extends Jar {
@@ -67,29 +67,67 @@ class War extends Jar {
         return webInf.addChild()
     }
 
+    /**
+     * Adds some content to the {@code WEB-INF} directory for this WAR archive.
+     *
+     * <p>The given closure is executed to configure a {@link CopySpec}. The {@code CopySpec} is passed to the closure
+     * as its delegate.
+     *
+     * @param configureClosure The closure to execute
+     * @return The newly created {@code CopySpec}.
+     */
     CopySpec webInf(Closure configureClosure) {
         return ConfigureUtil.configure(configureClosure, getWebInf())
     }
 
+    /**
+     * Returns the classpath to include in the WAR archive. Any JAR or ZIP files in this classpath are included in the
+     * {@code WEB-INF/lib} directory. Any directories in this classpath are included in the {@code WEB-INF/classes}
+     * directory.
+     *
+     * @return The classpath. Returns an empty collection when there is no classpath to include in the WAR.
+     */
     @InputFiles @Optional
     FileCollection getClasspath() {
         return classpath
     }
 
+    /**
+     * Sets the classpath to include in the WAR archive.
+     *
+     * @param classpath The classpath. Must not be null.
+     */
     void setClasspath(Object classpath) {
         this.classpath = project.files(classpath)
     }
 
+    /**
+     * Adds files to the classpath to include in the WAR archive.
+     *
+     * @param classpath The files to add. These are evaluated as for {@link org.gradle.api.Project#files(Object [])}
+     */
     void classpath(Object... classpath) {
         FileCollection oldClasspath = getClasspath()
         this.classpath = project.files(oldClasspath ?: [], classpath)
     }
 
+    /**
+     * Returns the {@code web.xml} file to include in the WAR archive. When {@code null}, no {@code web.xml} file is
+     * included in the WAR.
+     *
+     * @return The {@code web.xml} file.
+     */
     @InputFile @Optional
     public File getWebXml() {
         return webXml;
     }
 
+    /**
+     * Sets the {@code web.xml} file to include in the WAR archive. When {@code null}, no {@code web.xml} file is
+     * included in the WAR.
+     *
+     * @param webXml The {@code web.xml} file. Maybe null.
+     */
     public void setWebXml(File webXml) {
         this.webXml = webXml;
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
index 5cc5c5a..e67dbdd 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
@@ -31,39 +31,79 @@ public abstract class AbstractCompile extends SourceTask {
 
     @TaskAction
     protected abstract void compile();
-    
+
+    /**
+     * Returns the classpath to use to compile the source files.
+     *
+     * @return The classpath.
+     */
     @InputFiles
     public FileCollection getClasspath() {
         return classpath;
     }
 
+    /**
+     * Sets the classpath to use to compile the source files.
+     *
+     * @param configuration The classpath. Must not be null, but may be empty.
+     */
     public void setClasspath(FileCollection configuration) {
         this.classpath = configuration;
     }
 
+    /**
+     * Returns the directory to generate the {@code .class} files into.
+     *
+     * @return The destination directory.
+     */
     @OutputDirectory
     public File getDestinationDir() {
         return destinationDir;
     }
 
+    /**
+     * Sets the directory to generate the {@code .class} files into.
+     *
+     * @param destinationDir The destination directory. Must not be null.
+     */
     public void setDestinationDir(File destinationDir) {
         this.destinationDir = destinationDir;
     }
 
+    /**
+     * Returns the Java language level to use to compile the source files.
+     *
+     * @return The source language level.
+     */
     @Input
     public String getSourceCompatibility() {
         return sourceCompatibility;
     }
 
+    /**
+     * Sets the Java language level to use to compile the source files.
+     *
+     * @return The source language level. Must not be null.
+     */
     public void setSourceCompatibility(String sourceCompatibility) {
         this.sourceCompatibility = sourceCompatibility;
     }
 
+    /**
+     * Returns the target JVM to generate the {@code .class} files for.
+     *
+     * @return The target JVM.
+     */
     @Input
     public String getTargetCompatibility() {
         return targetCompatibility;
     }
 
+    /**
+     * Sets the target JVM to generate the {@code .class} files for.
+     *
+     * @param targetCompatibility The target JVM. Must not be null.
+     */
     public void setTargetCompatibility(String targetCompatibility) {
         this.targetCompatibility = targetCompatibility;
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractOptions.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractOptions.groovy
index 42d8eae..9accbfc 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractOptions.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractOptions.groovy
@@ -46,7 +46,7 @@ class AbstractOptions {
     // todo: change modifier to private when GROOVY-2565 is fixed.
     protected boolean isOptionField(Field field) {
         ((field.getModifiers() & Modifier.STATIC) == 0) &&
-                (!field.getName().equals("metaClass")) &&
+                (field.getName() != "metaClass") &&
                 (!excludedFieldsFromOptionMap().contains(field.name))
     }
 
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/Compile.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/Compile.java
index 7003dc9..59a7457 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/Compile.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/Compile.java
@@ -30,7 +30,7 @@ import java.io.File;
 
 /**
  * Compiles Java source files.
- * 
+ *
  * @author Hans Dockter
  */
 public class Compile extends AbstractCompile {
@@ -65,6 +65,11 @@ public class Compile extends AbstractCompile {
         this.dependencyCacheDir = dependencyCacheDir;
     }
 
+    /**
+     * Returns the compilation options.
+     *
+     * @return The compilation options.
+     */
     @Nested
     public CompileOptions getOptions() {
         return javaCompiler.getCompileOptions();
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/CompileOptions.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/CompileOptions.groovy
index f594470..3c50457 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/CompileOptions.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/CompileOptions.groovy
@@ -24,33 +24,89 @@ import org.gradle.api.tasks.Optional
  * @author Hans Dockter
  */
 class CompileOptions extends AbstractOptions {
+    /**
+     * Specifies whether the compile task should fail when compilation fails. The default is {@code true}.
+     */
     @Input
     boolean failOnError = true
     boolean verbose = false
     boolean listFiles = false
+
+    /**
+     * Specifies whether to log details of usage of deprecated members or classes. The default is {@code false}.
+     */
     boolean deprecation = false
+
+    /**
+     * Specifies whether to log warning messages. The default is {@code true}.
+     */
     boolean warnings = true
+
+    /**
+     * The source encoding name. Uses the platform default encoding if not specified. The default is {@code null}.
+     */
     @Input @Optional
     String encoding = null
     @Input
     boolean optimize
+
+    /**
+     * Specifies whether debugging information should be included in the generated {@code .class} files. The default
+     * is {@code true}.
+     */
     @Input
     boolean debug = true
+
+    /**
+     * The options for debugging information generation.
+     */
     @Nested
     DebugOptions debugOptions = new DebugOptions()
+
+    /**
+     * Specifies whether to run the compiler in a child process. The default is {@code false.
+     */
     boolean fork = false
+
+    /**
+     * The options for running the compiler in a child process.
+     */
     @Nested
     ForkOptions forkOptions = new ForkOptions()
+
+    /**
+     * Specifies whether to use the Ant {@code <depend>} task.
+     */
     boolean useDepend = false
+
+    /**
+     * The options for using the Ant {@code <depend>} task.
+     */
     DependOptions dependOptions = new DependOptions()
+
+    /**
+     * The compiler to use.
+     */
     @Input @Optional
     String compiler = null
     @Input
     boolean includeJavaRuntime = false
+
+    /**
+     * The bootstrap classpath to use when compiling.
+     */
     @Input @Optional
     String bootClasspath = null
+
+    /**
+     * The extension dirs to use when compiling.
+     */
     @Input @Optional
     String extensionDirs = null
+
+    /**
+     * The arguments to pass to the compiler.
+     */
     @Input
     List compilerArgs = []
 
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/ForkOptions.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/ForkOptions.groovy
index c816b7d..56f9dfe 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/ForkOptions.groovy
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/ForkOptions.groovy
@@ -23,16 +23,29 @@ import org.gradle.api.tasks.Optional
  * @author Hans Dockter
  */
 class ForkOptions extends AbstractOptions {
+    /**
+     * The executable to use to fork the compiler.
+     */
     @Input @Optional
     String executable = null
+
+    /**
+     * The initial heap size for the compiler process.
+     */
     String memoryInitialSize = null
+
+    /**
+     * The maximum heap size for the compiler process.
+     */
     String memoryMaximumSize = null
     String tempDir = null
 
+    /**
+     * The JVM command-line arguments for the compiler process.
+     */
     List jvmArgs
 
     Map fieldName2AntMap() {
         [tempDir: 'tempdir']
     }
-    
 }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java
index 7244c09..d8326d6 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java
@@ -33,7 +33,7 @@ import java.util.Collection;
 import java.util.List;
 
 /**
- * Compiles Groovy and Java source files.
+ * Compiles Groovy source files, and optionally, Java source files.
  *
  * @author Hans Dockter
  */
@@ -68,24 +68,41 @@ public class GroovyCompile extends AbstractCompile {
     }
 
     /**
-     * Gets the options for the groovyc compilation. To set specific options for the nested javac compilation,
-     * use {@link #getOptions()}.
+     * Gets the options for the Groovy compilation. To set specific options for the nested Java compilation, use {@link
+     * #getOptions()}.
+     *
+     * @return The Groovy compile options. Never returns null.
      */
     @Nested
     public GroovyCompileOptions getGroovyOptions() {
         return compiler.getGroovyCompileOptions();
     }
 
+    /**
+     * Returns the options for Java compilation.
+     *
+     * @return The java compile options. Never returns null.
+     */
     @Nested
     public CompileOptions getOptions() {
         return compiler.getCompileOptions();
     }
 
+    /**
+     * Returns the classpath containing the version of Groovy to use for compilation.
+     *
+     * @return The classpath.
+     */
     @InputFiles
     public FileCollection getGroovyClasspath() {
         return groovyClasspath;
     }
 
+    /**
+     * Sets the classpath containing the version of Groovy to use for compilation.
+     *
+     * @param groovyClasspath The classpath. Must not be null.
+     */
     public void setGroovyClasspath(FileCollection groovyClasspath) {
         this.groovyClasspath = groovyClasspath;
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java
index 21b3b02..0911f26 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java
@@ -24,13 +24,16 @@ import org.gradle.api.logging.LogLevel;
 import org.gradle.api.tasks.*;
 
 import java.io.File;
+import java.io.Serializable;
 import java.util.*;
 
 /**
- * Generates HTML API documentation for Groovy and Java classes. It uses Groovy's Groovydoc tool for this. Please note that the
- * Groovydoc tool has some severe limitations at the moment (for example no doc for properties comments). The version of
- * the Groovydoc that is used, is the one from the Groovy defined in the build script. Please note also, that the
- * Groovydoc tool prints to System.out for many of its statements and does circumvents our logging currently.
+ * <p>Generates HTML API documentation for Groovy source, and optionally, Java source.
+ *
+ * <p>This task uses Groovy's Groovydoc tool to generate the API documentation. Please note that the Groovydoc tool has
+ * some severe limitations at the moment (for example no doc for properties comments). The version of the Groovydoc that
+ * is used, is the one from the Groovy defined in the build script. Please note also, that the Groovydoc tool prints to
+ * System.out for many of its statements and does circumvents our logging currently.
  *
  * @author Hans Dockter
  */
@@ -123,26 +126,28 @@ public class Groovydoc extends SourceTask {
     /**
      * Returns whether to create class and package usage pages.
      */
+    @Input
     public boolean isUse() {
         return use;
     }
 
     /**
-     * Set's whether to create class and package usage pages. Defaults to false.
+     * Sets whether to create class and package usage pages.
      */
     public void setUse(boolean use) {
         this.use = use;
     }
 
     /**
-     * Returns the browser window title for the documentation.
+     * Returns the browser window title for the documentation. Set to {@code null} when there is no window title.
      */
+    @Input @Optional
     public String getWindowTitle() {
         return windowTitle;
     }
 
     /**
-     * Set's the browser window title for the documentation.
+     * Sets the browser window title for the documentation.
      *
      * @param windowTitle A text for the windows title
      */
@@ -151,14 +156,15 @@ public class Groovydoc extends SourceTask {
     }
 
     /**
-     * Returns the title for the package index(first) page. Returns null if not set.
+     * Returns the title for the package index(first) page. Set to {@code null} when there is no document title.
      */
+    @Input @Optional
     public String getDocTitle() {
         return docTitle;
     }
 
     /**
-     * Set's title for the package index(first) page (optional).
+     * Sets title for the package index(first) page (optional).
      *
      * @param docTitle the docTitle as html-code
      */
@@ -167,14 +173,15 @@ public class Groovydoc extends SourceTask {
     }
 
     /**
-     * Returns the html header for each page. Returns null if not set.
+     * Returns the html header for each page. Set to {@code null} when there is no header.
      */
+    @Input @Optional
     public String getHeader() {
         return header;
     }
 
     /**
-     * Set's header text for each page (optional).
+     * Sets header text for each page (optional).
      *
      * @param header the header as html-code
      */
@@ -183,14 +190,15 @@ public class Groovydoc extends SourceTask {
     }
 
     /**
-     * Returns the html footer for each page. Returns null if not set.
+     * Returns the html footer for each page. Set to {@code null} when there is no footer.
      */
+    @Input @Optional
     public String getFooter() {
         return footer;
     }
 
     /**
-     * Set's footer text for each page (optional).
+     * Sets footer text for each page (optional).
      *
      * @param footer the footer as html-code
      */
@@ -199,14 +207,14 @@ public class Groovydoc extends SourceTask {
     }
 
     /**
-     * Returns a html file to be used for overview documentation. Returns null if such a file is not set.
+     * Returns a html file to be used for overview documentation. Set to {@code null} when there is no overview file.
      */
     public String getOverview() {
         return overview;
     }
 
     /**
-     * Set's a html file to be used for overview documentation (optional).
+     * Sets a html file to be used for overview documentation (optional).
      */
     public void setOverview(String overview) {
         this.overview = overview;
@@ -215,21 +223,22 @@ public class Groovydoc extends SourceTask {
     /**
      * Returns whether to include all classes and members (i.e. including private ones).
      */
+    @Input
     public boolean isIncludePrivate() {
         return includePrivate;
     }
 
     /**
-     * Set's whether to include all classes and members (i.e. including private ones) if set to true. Defaults to
-     * false.
+     * Sets whether to include all classes and members (i.e. including private ones) if set to true.
      */
     public void setIncludePrivate(boolean includePrivate) {
         this.includePrivate = includePrivate;
     }
 
     /**
-     * Returns links to groovydoc/javadoc output at the given URL.
+     * Returns the links to groovydoc/javadoc output at the given URL.
      */
+    @Input
     public Set<Link> getLinks() {
         return Collections.unmodifiableSet(links);
     }
@@ -238,7 +247,7 @@ public class Groovydoc extends SourceTask {
      * Sets links to groovydoc/javadoc output at the given URL.
      *
      * @param links The links to set
-     * @see #link(String, String[])
+     * @see #link(String, String...)
      */
     public void setLinks(Set<Link> links) {
         this.links = links;
@@ -257,7 +266,7 @@ public class Groovydoc extends SourceTask {
     /**
      * A Link class represent a link between groovydoc/javadoc output and url.
      */
-    public static class Link {
+    public static class Link implements Serializable {
         private List<String> packages = new ArrayList<String>();
         private String url;
 
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Javadoc.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Javadoc.java
index f4f7bf0..62a91f0 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Javadoc.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Javadoc.java
@@ -19,10 +19,7 @@ package org.gradle.api.tasks.javadoc;
 import org.gradle.api.GradleException;
 import org.gradle.api.file.FileCollection;
 import org.gradle.api.internal.file.SimpleFileCollection;
-import org.gradle.api.tasks.InputFiles;
-import org.gradle.api.tasks.OutputDirectory;
-import org.gradle.api.tasks.SourceTask;
-import org.gradle.api.tasks.TaskAction;
+import org.gradle.api.tasks.*;
 import org.gradle.external.javadoc.internal.JavadocExecHandleBuilder;
 import org.gradle.external.javadoc.MinimalJavadocOptions;
 import org.gradle.external.javadoc.StandardJavadocDocletOptions;
@@ -103,7 +100,8 @@ public class Javadoc extends SourceTask {
 
     private void executeExternalJavadoc() {
         javadocExecHandleBuilder.setExecutable(executable);
-        javadocExecHandleBuilder.execDirectory(getProject().getRootDir()).options(options).optionsFile(getOptionsFile());
+        javadocExecHandleBuilder.execDirectory(getProject().getRootDir()).options(options).optionsFile(
+                getOptionsFile());
 
         ExecAction execAction = javadocExecHandleBuilder.getExecHandle();
         if (!failOnError) {
@@ -162,6 +160,8 @@ public class Javadoc extends SourceTask {
      *
      * @return The title, possibly null.
      */
+    @Input
+    @Optional
     public String getTitle() {
         return title;
     }
@@ -184,7 +184,7 @@ public class Javadoc extends SourceTask {
 
     /**
      * Sets whether javadoc generation is accompanied by verbose output or not. The verbose output is done via println
-     * (by the underlying ant task). Thus it is not catched by our logging.
+     * (by the underlying ant task). Thus it is not handled by our logging.
      *
      * @param verbose Whether the output should be verbose.
      */
@@ -194,23 +194,49 @@ public class Javadoc extends SourceTask {
         }
     }
 
+    /**
+     * Returns the classpath to use to resolve type references in the source code.
+     *
+     * @return The classpath.
+     */
     @InputFiles
     public FileCollection getClasspath() {
         return classpath;
     }
 
-    public void setClasspath(FileCollection configuration) {
-        this.classpath = configuration;
+    /**
+     * Sets the classpath to use to resolve type references in this source code.
+     *
+     * @param classpath The classpath. Must not be null.
+     */
+    public void setClasspath(FileCollection classpath) {
+        this.classpath = classpath;
     }
 
+    /**
+     * Returns the javadoc generation options.
+     *
+     * @return The options. Never returns null.
+     */
+    @Nested
     public MinimalJavadocOptions getOptions() {
         return options;
     }
 
+    /**
+     * Sets the javadoc generation options.
+     *
+     * @param options The options. Must not be null.
+     */
     public void setOptions(MinimalJavadocOptions options) {
         this.options = options;
     }
 
+    /**
+     * Specifies whether this task should fail when errors are encountered during javadoc generation. When {@code true},
+     * this task will fail on javadoc error. When {@code false}, this task will ignore javadoc errors.
+     */
+    @Input
     public boolean isFailOnError() {
         return failOnError;
     }
@@ -223,6 +249,13 @@ public class Javadoc extends SourceTask {
         return new File(getTemporaryDir(), "javadoc.options");
     }
 
+    /**
+     * Returns the javadoc executable to use to generation the javadoc. When {@code null}, the javadoc executable for
+     * the current jvm is used.
+     *
+     * @return The executable. May be null.
+     */
+    @Input @Optional
     public String getExecutable() {
         return executable;
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
index 632e777..3425643 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
@@ -585,7 +585,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
 
     public TestFramework testFramework(Closure testFrameworkConfigure) {
         if (testFramework == null) {
-            return useJUnit(testFrameworkConfigure);
+            useJUnit(testFrameworkConfigure);
         }
 
         return testFramework;
@@ -594,7 +594,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * <p>Returns the test options options.</p>
      *
-     * <p>Be sure to call the appropriate {@link #useJUnit} or {@link #useTestNG} method before using this method.</p>
+     * <p>Be sure to call the appropriate {@link #useJUnit()} or {@link #useTestNG()} method before using this method.</p>
      *
      * @return The testframework options.
      */
@@ -630,8 +630,8 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * Specifies that JUnit should be used to execute the tests.
      */
-    public TestFramework useJUnit() {
-        return useJUnit(null);
+    public void useJUnit() {
+        useJUnit(null);
     }
 
     /**
@@ -640,15 +640,15 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
      * @param testFrameworkConfigure A closure used to configure the JUint options. This closure is passed an instance
      * of type {@link org.gradle.api.tasks.testing.junit.JUnitOptions}.
      */
-    public TestFramework useJUnit(Closure testFrameworkConfigure) {
-        return useTestFramework(new JUnitTestFramework(this), testFrameworkConfigure);
+    public void useJUnit(Closure testFrameworkConfigure) {
+        useTestFramework(new JUnitTestFramework(this), testFrameworkConfigure);
     }
 
     /**
      * Specifies that TestNG should be used to execute the tests.
      */
-    public TestFramework useTestNG() {
-        return useTestNG(null);
+    public void useTestNG() {
+        useTestNG(null);
     }
 
     /**
@@ -657,10 +657,13 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
      * @param testFrameworkConfigure A closure used to configure the JUint options. This closure is passed an instance
      * of type {@link org.gradle.api.tasks.testing.junit.JUnitOptions}.
      */
-    public TestFramework useTestNG(Closure testFrameworkConfigure) {
-        return useTestFramework(new TestNGTestFramework(this), testFrameworkConfigure);
+    public void useTestNG(Closure testFrameworkConfigure) {
+        useTestFramework(new TestNGTestFramework(this), testFrameworkConfigure);
     }
 
+    /**
+     * Returns the classpath to use to execute the tests.
+     */
     @InputFiles
     public FileCollection getClasspath() {
         return classpath;
@@ -670,6 +673,9 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
         this.classpath = classpath;
     }
 
+    /**
+     * Specifies whether the test report should be generated.
+     */
     public boolean isTestReport() {
         return testReport;
     }
@@ -686,6 +692,9 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
         this.testReport = false;
     }
 
+    /**
+     * Returns the directories containing the test source.
+     */
     @InputFiles
     public List<File> getTestSrcDirs() {
         return testSrcDirs;
@@ -695,6 +704,11 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
         this.testSrcDirs = testSrcDir;
     }
 
+    /**
+     * Specifies whether test classes should be detected. When {@code true} the classes which match the include and
+     * exclude patterns are scanned for test classes, and any found are executed. When {@code false} the classes which
+     * match the include and exclude patterns are executed.
+     */
     public boolean isScanForTestClasses() {
         return scanForTestClasses;
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/TestResult.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/TestResult.java
index 8d0be7b..9db7c8d 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/TestResult.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/TestResult.java
@@ -16,6 +16,8 @@
 
 package org.gradle.api.tasks.testing;
 
+import java.util.List;
+
 /**
  * Describes a test result.
  */
@@ -23,7 +25,9 @@ public interface TestResult {
     /**
      * The final status of a test.
      */
-    public enum ResultType {SUCCESS, FAILURE, SKIPPED}
+    public enum ResultType {
+        SUCCESS, FAILURE, SKIPPED
+    }
 
     /**
      * Returns the type of result.  Generally one wants it to be SUCCESS!
@@ -34,13 +38,19 @@ public interface TestResult {
 
     /**
      * If the test failed with an exception, this will be the exception.  Some test frameworks do not fail without an
-     * exception (JUnit), so in those cases this method will never return null.  If the resultType is not FAILURE an
-     * IllegalStateException is thrown.
+     * exception (JUnit), so in those cases this method will never return null.
      *
      * @return The exception, if any, logged for this test.  If none, a null is returned.
-     * @throws IllegalStateException If the result type is anything other than FAILURE.
      */
-    Throwable getException(); // throws exception if type !=  FAILURE
+    Throwable getException();
+
+    /**
+     * If the test failed with any exceptions, this will contain the exceptions.  Some test frameworks do not fail
+     * without an exception (JUnit), so in those cases this method will never return null.
+     *
+     * @return The exceptions, if any, logged for this test.  If none, an empty list is returned.
+     */
+    List<Throwable> getExceptions();
 
     /**
      * Returns the time when this test started execution.
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/javadoc/MinimalJavadocOptions.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/javadoc/MinimalJavadocOptions.java
index 62a9df5..cec29b6 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/javadoc/MinimalJavadocOptions.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/javadoc/MinimalJavadocOptions.java
@@ -16,6 +16,9 @@
 
 package org.gradle.external.javadoc;
 
+import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.InputFiles;
+import org.gradle.api.tasks.Optional;
 import org.gradle.process.ExecSpec;
 
 import java.io.File;
@@ -28,12 +31,14 @@ import java.util.List;
  * @author Tom Eyckmans
  */
 public interface MinimalJavadocOptions {
+    @Input @Optional
     String getOverview();
 
     void setOverview(String overview);
 
     MinimalJavadocOptions overview(String overview);
 
+    @Input @Optional
     JavadocMemberLevel getMemberLevel();
 
     void setMemberLevel(JavadocMemberLevel memberLevel);
@@ -48,18 +53,21 @@ public interface MinimalJavadocOptions {
 
     MinimalJavadocOptions showAll();
 
+    @Input @Optional
     String getDoclet();
 
     void setDoclet(String docletClass);
 
     MinimalJavadocOptions doclet(String docletClass);
 
+    @InputFiles
     List<File> getDocletpath();
 
     void setDocletpath(List<File> docletpath);
 
     MinimalJavadocOptions docletpath(File ... docletpath);
 
+    @Input @Optional
     String getSource();
 
     void setSource(String source);
@@ -74,12 +82,14 @@ public interface MinimalJavadocOptions {
 
     MinimalJavadocOptions classpath(File ... classpath);
 
+    @InputFiles
     List<File> getBootClasspath();
 
     void setBootClasspath(List<File> bootClasspath);
 
     MinimalJavadocOptions bootClasspath(File ... bootClasspath);
 
+    @InputFiles
     List<File> getExtDirs();
 
     void setExtDirs(List<File> extDirs);
@@ -96,6 +106,7 @@ public interface MinimalJavadocOptions {
 
     MinimalJavadocOptions quiet();
 
+    @Input
     boolean isBreakIterator();
 
     void setBreakIterator(boolean breakIterator);
@@ -104,12 +115,14 @@ public interface MinimalJavadocOptions {
 
     MinimalJavadocOptions breakIterator();
 
+    @Input @Optional
     String getLocale();
 
     void setLocale(String locale);
 
     MinimalJavadocOptions locale(String locale);
 
+    @Input @Optional
     String getEncoding();
 
     void setEncoding(String encoding);
@@ -134,12 +147,14 @@ public interface MinimalJavadocOptions {
 
     MinimalJavadocOptions destinationDirectory(File directory);
 
+    @Input @Optional
     String getWindowTitle();
 
     void setWindowTitle(String windowTitle);
 
     StandardJavadocDocletOptions windowTitle(String windowTitle);
 
+    @Input @Optional
     String getHeader();
 
     void setHeader(String header);
diff --git a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
index 2b7accb..ffda8e6 100644
--- a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
+++ b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassProcessorTest.groovy
@@ -13,9 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
-
 package org.gradle.api.internal.tasks.testing.junit
 
 import junit.framework.TestCase
@@ -42,6 +39,7 @@ import static org.junit.Assert.*
 import org.gradle.logging.StandardOutputRedirector
 import org.junit.BeforeClass
 import junit.extensions.TestSetup
+import org.junit.After
 
 @RunWith(JMock.class)
 class JUnitTestClassProcessorTest {
@@ -51,7 +49,7 @@ class JUnitTestClassProcessorTest {
     private final JUnitTestClassProcessor processor = new JUnitTestClassProcessor(tmpDir.dir, new LongIdGenerator(), {} as StandardOutputRedirector);
 
     @Test
-    public void executesATestClass() {
+    public void executesAJUnit4TestClass() {
         context.checking {
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
             will { TestDescriptorInternal suite, TestStartEvent event ->
@@ -310,47 +308,47 @@ class JUnitTestClassProcessorTest {
     }
 
     @Test
-    public void executesATestClassWithBrokenConstructor() {
+    public void executesATestClassWithBrokenBeforeMethod() {
         context.checking {
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
             will { TestDescriptorInternal suite ->
-                assertThat(suite.name, equalTo(ATestClassWithBrokenConstructor.class.name))
+                assertThat(suite.name, equalTo(ATestClassWithBrokenBeforeMethod.class.name))
             }
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
             will { TestDescriptorInternal test ->
-                assertThat(test.id, equalTo(2L))
                 assertThat(test.name, equalTo('test'))
-                assertThat(test.className, equalTo(ATestClassWithBrokenConstructor.class.name))
+                assertThat(test.className, equalTo(ATestClassWithBrokenBeforeMethod.class.name))
             }
-            one(resultProcessor).failure(2L, ATestClassWithBrokenConstructor.failure)
+            one(resultProcessor).failure(2L, ATestClassWithBrokenBeforeMethod.failure)
             one(resultProcessor).completed(withParam(equalTo(2L)), withParam(notNullValue()))
             will { id, TestCompleteEvent event ->
                 assertThat(event.resultType, nullValue())
             }
-            one(resultProcessor).completed(withParam(notNullValue()), withParam(notNullValue()))
+            one(resultProcessor).completed(withParam(equalTo(1L)), withParam(notNullValue()))
             will { id, TestCompleteEvent event ->
                 assertThat(event.resultType, nullValue())
             }
         }
 
         processor.startProcessing(resultProcessor);
-        processor.processTestClass(testClass(ATestClassWithBrokenConstructor.class));
+        processor.processTestClass(testClass(ATestClassWithBrokenBeforeMethod.class));
         processor.stop();
     }
 
     @Test
-    public void executesATestClassWithBrokenSetup() {
+    public void executesATestClassWithBrokenBeforeAndAfterMethod() {
         context.checking {
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
             will { TestDescriptorInternal suite ->
-                assertThat(suite.name, equalTo(ATestClassWithBrokenBeforeMethod.class.name))
+                assertThat(suite.name, equalTo(ATestClassWithBrokenBeforeAndAfterMethod.class.name))
             }
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
             will { TestDescriptorInternal test ->
                 assertThat(test.name, equalTo('test'))
-                assertThat(test.className, equalTo(ATestClassWithBrokenBeforeMethod.class.name))
+                assertThat(test.className, equalTo(ATestClassWithBrokenBeforeAndAfterMethod.class.name))
             }
-            one(resultProcessor).failure(2L, ATestClassWithBrokenBeforeMethod.failure)
+            one(resultProcessor).failure(2L, ATestClassWithBrokenBeforeAndAfterMethod.beforeFailure)
+            one(resultProcessor).failure(2L, ATestClassWithBrokenBeforeAndAfterMethod.afterFailure)
             one(resultProcessor).completed(withParam(equalTo(2L)), withParam(notNullValue()))
             will { id, TestCompleteEvent event ->
                 assertThat(event.resultType, nullValue())
@@ -362,11 +360,41 @@ class JUnitTestClassProcessorTest {
         }
 
         processor.startProcessing(resultProcessor);
-        processor.processTestClass(testClass(ATestClassWithBrokenBeforeMethod.class));
+        processor.processTestClass(testClass(ATestClassWithBrokenBeforeAndAfterMethod.class));
         processor.stop();
     }
 
     @Test
+    public void executesATestClassWithBrokenConstructor() {
+        context.checking {
+            one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
+            will { TestDescriptorInternal suite ->
+                assertThat(suite.name, equalTo(ATestClassWithBrokenConstructor.class.name))
+            }
+            one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
+            will { TestDescriptorInternal test ->
+                assertThat(test.id, equalTo(2L))
+                assertThat(test.name, equalTo('test'))
+                assertThat(test.className, equalTo(ATestClassWithBrokenConstructor.class.name))
+            }
+            one(resultProcessor).failure(2L, ATestClassWithBrokenConstructor.failure)
+            one(resultProcessor).completed(withParam(equalTo(2L)), withParam(notNullValue()))
+            will { id, TestCompleteEvent event ->
+                assertThat(event.resultType, nullValue())
+            }
+            one(resultProcessor).completed(withParam(notNullValue()), withParam(notNullValue()))
+            will { id, TestCompleteEvent event ->
+                assertThat(event.resultType, nullValue())
+            }
+        }
+
+        processor.startProcessing(resultProcessor);
+        processor.processTestClass(testClass(ATestClassWithBrokenConstructor.class));
+        processor.stop();
+    }
+
+
+    @Test
     public void executesATestClassWithBrokenClassSetup() {
         context.checking {
             one(resultProcessor).started(withParam(notNullValue()), withParam(notNullValue()))
@@ -501,6 +529,25 @@ public class ATestClassWithBrokenBeforeMethod {
     }
 }
 
+public class ATestClassWithBrokenBeforeAndAfterMethod {
+    static RuntimeException beforeFailure = new RuntimeException()
+    static RuntimeException afterFailure = new RuntimeException()
+
+    @Before
+    public void setup() {
+        throw beforeFailure.fillInStackTrace()
+    }
+
+    @After
+    public void teardown() {
+        throw afterFailure.fillInStackTrace()
+    }
+
+    @Test
+    public void test() {
+    }
+}
+
 public class ATestClassWithBrokenBeforeClassMethod {
     static RuntimeException failure = new RuntimeException()
 
diff --git a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapterTest.groovy b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapterTest.groovy
index 463b2b3..317c6fd 100644
--- a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapterTest.groovy
+++ b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/internal/tasks/testing/results/TestListenerAdapterTest.groovy
@@ -13,27 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-
-
-
-
-
 package org.gradle.api.internal.tasks.testing.results
 
+import org.gradle.api.internal.tasks.testing.TestCompleteEvent
+import org.gradle.api.internal.tasks.testing.TestDescriptorInternal
+import org.gradle.api.internal.tasks.testing.TestStartEvent
+import org.gradle.api.tasks.testing.TestDescriptor
 import org.gradle.api.tasks.testing.TestListener
 import org.gradle.api.tasks.testing.TestResult
+import org.gradle.api.tasks.testing.TestResult.ResultType
 import org.gradle.util.JUnit4GroovyMockery
 import org.jmock.integration.junit4.JMock
 import org.junit.Test
 import org.junit.runner.RunWith
-import static org.junit.Assert.*
+import static org.gradle.util.Matchers.*
 import static org.hamcrest.Matchers.*
-import org.gradle.api.tasks.testing.TestResult.ResultType
-import org.gradle.api.internal.tasks.testing.TestDescriptorInternal
-import org.gradle.api.internal.tasks.testing.TestStartEvent
-import org.gradle.api.internal.tasks.testing.TestCompleteEvent
-import org.gradle.api.tasks.testing.TestDescriptor
+import static org.junit.Assert.*
 
 @RunWith(JMock.class)
 class TestListenerAdapterTest {
@@ -55,6 +50,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(test))
                 assertThat(result.resultType, equalTo(ResultType.SUCCESS))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.startTime, equalTo(100L))
                 assertThat(result.endTime, equalTo(200L))
                 assertThat(result.testCount, equalTo(1L))
@@ -84,6 +81,7 @@ class TestListenerAdapterTest {
                 assertThat(t.descriptor, equalTo(test))
                 assertThat(result.resultType, equalTo(ResultType.FAILURE))
                 assertThat(result.exception, sameInstance(failure))
+                assertThat(result.exceptions, equalTo([failure]))
                 assertThat(result.startTime, equalTo(100L))
                 assertThat(result.endTime, equalTo(200L))
                 assertThat(result.testCount, equalTo(1L))
@@ -98,6 +96,39 @@ class TestListenerAdapterTest {
     }
 
     @Test
+    public void createsAResultForATestWithMultipleFailures() {
+        RuntimeException failure1 = new RuntimeException()
+        RuntimeException failure2 = new RuntimeException()
+
+        TestDescriptorInternal test = test('id')
+
+        context.checking {
+            one(listener).beforeTest(withParam(notNullValue()))
+            will { TestDescriptor t ->
+                assertThat(t.descriptor, equalTo(test))
+                assertThat(t.parent, nullValue())
+            }
+            one(listener).afterTest(withParam(notNullValue()), withParam(notNullValue()))
+            will { TestDescriptor t, TestResult result ->
+                assertThat(t.descriptor, equalTo(test))
+                assertThat(result.resultType, equalTo(ResultType.FAILURE))
+                assertThat(result.exception, sameInstance(failure1))
+                assertThat(result.exceptions, equalTo([failure1, failure2]))
+                assertThat(result.startTime, equalTo(100L))
+                assertThat(result.endTime, equalTo(200L))
+                assertThat(result.testCount, equalTo(1L))
+                assertThat(result.successfulTestCount, equalTo(0L))
+                assertThat(result.failedTestCount, equalTo(1L))
+            }
+        }
+
+        adapter.started(test, new TestStartEvent(100L))
+        adapter.failure('id', failure1)
+        adapter.failure('id', failure2)
+        adapter.completed('id', new TestCompleteEvent(200L))
+    }
+
+    @Test
     public void createsAResultForASkippedTest() {
         TestDescriptorInternal test = test('id')
 
@@ -111,6 +142,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(test))
                 assertThat(result.resultType, equalTo(ResultType.SKIPPED))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.startTime, equalTo(100L))
                 assertThat(result.endTime, equalTo(200L))
                 assertThat(result.testCount, equalTo(1L))
@@ -137,6 +170,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite))
                 assertThat(result.resultType, equalTo(ResultType.SUCCESS))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.startTime, equalTo(100L))
                 assertThat(result.endTime, equalTo(200L))
                 assertThat(result.testCount, equalTo(0L))
@@ -173,6 +208,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite))
                 assertThat(result.resultType, equalTo(ResultType.SUCCESS))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(1L))
                 assertThat(result.successfulTestCount, equalTo(1L))
                 assertThat(result.failedTestCount, equalTo(0L))
@@ -213,6 +250,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite))
                 assertThat(result.resultType, equalTo(ResultType.FAILURE))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(2L))
                 assertThat(result.successfulTestCount, equalTo(1L))
                 assertThat(result.failedTestCount, equalTo(1L))
@@ -249,6 +288,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite))
                 assertThat(result.resultType, equalTo(ResultType.SUCCESS))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(1L))
                 assertThat(result.successfulTestCount, equalTo(0L))
                 assertThat(result.failedTestCount, equalTo(0L))
@@ -281,6 +322,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite1))
                 assertThat(result.resultType, equalTo(ResultType.SUCCESS))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(1L))
                 assertThat(result.successfulTestCount, equalTo(1L))
                 assertThat(result.failedTestCount, equalTo(0L))
@@ -289,6 +332,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(suite2))
                 assertThat(result.resultType, equalTo(ResultType.FAILURE))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(1L))
                 assertThat(result.successfulTestCount, equalTo(0L))
                 assertThat(result.failedTestCount, equalTo(1L))
@@ -297,6 +342,8 @@ class TestListenerAdapterTest {
             will { TestDescriptor t, TestResult result ->
                 assertThat(t.descriptor, equalTo(root))
                 assertThat(result.resultType, equalTo(ResultType.FAILURE))
+                assertThat(result.exception, nullValue())
+                assertThat(result.exceptions, isEmpty())
                 assertThat(result.testCount, equalTo(2L))
                 assertThat(result.successfulTestCount, equalTo(1L))
                 assertThat(result.failedTestCount, equalTo(1L))
@@ -331,6 +378,7 @@ class TestListenerAdapterTest {
                 assertThat(t.descriptor, equalTo(suite))
                 assertThat(result.resultType, equalTo(ResultType.FAILURE))
                 assertThat(result.exception, sameInstance(failure))
+                assertThat(result.exceptions, equalTo([failure]))
             }
         }
 
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/ScalaSourceSet.java b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/ScalaSourceSet.java
index 64d119e..354cfb9 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/ScalaSourceSet.java
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/ScalaSourceSet.java
@@ -20,21 +20,22 @@ import org.gradle.api.file.FileTree;
 import org.gradle.api.file.SourceDirectorySet;
 
 /**
- * A {@code ScalaSourceSetConvention} defines the properties and methods added to a {@link org.gradle.api.tasks.SourceSet}
- * by the {@link org.gradle.api.plugins.scala.ScalaPlugin}.
+ * A {@code ScalaSourceSetConvention} defines the properties and methods added to a {@link
+ * org.gradle.api.tasks.SourceSet} by the {@link org.gradle.api.plugins.scala.ScalaPlugin}.
  */
 public interface ScalaSourceSet {
     /**
-     * Returns the source to be compiled by the Scala compiler for this source set. This may contain both Java
-     * and Scala source files.
+     * Returns the source to be compiled by the Scala compiler for this source set. This may contain both Java and Scala
+     * source files.
      *
      * @return The Scala source. Never returns null.
      */
     SourceDirectorySet getScala();
 
     /**
-     * Configures the Scala source for this set. The given closure is used to configure the {@code SourceDirectorySet}
-     * which contains the Scala source.
+     * Configures the Scala source for this set.
+     *
+     * <p>The given closure is used to configure the {@link SourceDirectorySet} which contains the Scala source.
      *
      * @param configureClosure The closure to use to configure the Scala source.
      * @return this
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaCompile.java b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaCompile.java
index eb6e7c7..7b69a60 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaCompile.java
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaCompile.java
@@ -29,7 +29,7 @@ import org.gradle.api.tasks.compile.AbstractCompile;
 import org.gradle.api.tasks.compile.CompileOptions;
 
 /**
- * Compiles Scala and Java source files.
+ * Compiles Scala source files, and optionally, Java source files.
  */
 public class ScalaCompile extends AbstractCompile {
     private FileCollection scalaClasspath;
@@ -42,6 +42,9 @@ public class ScalaCompile extends AbstractCompile {
         compiler = new IncrementalScalaCompiler(new DefaultScalaJavaJointCompiler(scalaCompiler, javaCompiler), getOutputs());
     }
 
+    /**
+     * Returns the classpath to use to load the Scala compiler.
+     */
     @InputFiles
     public FileCollection getScalaClasspath() {
         return scalaClasspath;
@@ -59,11 +62,17 @@ public class ScalaCompile extends AbstractCompile {
         this.compiler = compiler;
     }
 
+    /**
+     * Returns the Scala compilation options.
+     */
     @Nested
     public ScalaCompileOptions getScalaCompileOptions() {
         return compiler.getScalaCompileOptions();
     }
 
+    /**
+     * Returns the Java compilation options.
+     */
     @Nested
     public CompileOptions getOptions() {
         return compiler.getCompileOptions();
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
index 987bb01..7008439 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
@@ -17,10 +17,7 @@ package org.gradle.api.tasks.scala;
 
 import org.gradle.api.file.FileCollection;
 import org.gradle.api.internal.project.IsolatedAntBuilder;
-import org.gradle.api.tasks.InputFiles;
-import org.gradle.api.tasks.OutputDirectory;
-import org.gradle.api.tasks.SourceTask;
-import org.gradle.api.tasks.TaskAction;
+import org.gradle.api.tasks.*;
 import org.gradle.util.GUtil;
 
 import java.io.File;
@@ -46,6 +43,9 @@ public class ScalaDoc extends SourceTask {
         this.antScalaDoc = antScalaDoc;
     }
 
+    /**
+     * Returns the directory to generate the API documentation into.
+     */
     @OutputDirectory
     public File getDestinationDir() {
         return destinationDir;
@@ -69,6 +69,9 @@ public class ScalaDoc extends SourceTask {
         this.classpath = classpath;
     }
 
+    /**
+     * Returns the classpath to use to load the ScalaDoc tool.
+     */
     @InputFiles
     public FileCollection getScalaClasspath() {
         return scalaClasspath;
@@ -78,6 +81,10 @@ public class ScalaDoc extends SourceTask {
         this.scalaClasspath = scalaClasspath;
     }
 
+    /**
+     * Returns the ScalaDoc generation options.
+     */
+    @Nested
     public ScalaDocOptions getScalaDocOptions() {
         return scalaDocOptions;
     }
@@ -86,6 +93,10 @@ public class ScalaDoc extends SourceTask {
         this.scalaDocOptions = scalaDocOptions;
     }
 
+    /**
+     * Returns the documentation title.
+     */
+    @Input @Optional
     public String getTitle() {
         return title;
     }
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDocOptions.groovy b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDocOptions.groovy
index 7e30ab9..29ccdbd 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDocOptions.groovy
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDocOptions.groovy
@@ -16,58 +16,71 @@
 package org.gradle.api.tasks.scala
 
 import org.gradle.api.tasks.compile.AbstractOptions
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Optional
+import org.gradle.api.tasks.InputFile
 
 public class ScalaDocOptions extends AbstractOptions {
 
     /**
      * Generate deprecation information.
      */
+    @Input
     boolean deprecation = true
 
     /**
      * Generate unchecked information.
      */
+    @Input
     boolean unchecked = true
 
     /**
      * Text to appear in the window title.
      */
+    @Input @Optional
     String windowTitle
 
     /**
      * Html text to appear in the main frame title.
      */
+    @Input @Optional
     String docTitle
 
     /**
      * Html text to appear in the header for each page.
      */
+    @Input @Optional
     String header
 
     /**
      * Html text to appear in the footer for each page.
      */
+    @Input @Optional
     String footer
 
     /**
      * Html text to appear in the top text for each page.
      */
+    @Input @Optional
     String top
 
     /**
      * Html text to appear in the bottom text for each page.
      */
+    @Input @Optional
     String bottom
 
     /**
      * Style sheet to override default style.
      */
+    @InputFile @Optional
     File styleSheet
 
     /**
      * Additional parameters passed to the compiler.
      * Each parameter must start with '-'.
      */
+    @Input @Optional
     List<String> additionalParameters
 
 
diff --git a/subprojects/gradle-ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy b/subprojects/gradle-ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
index fa5287f..eb750c1 100644
--- a/subprojects/gradle-ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
+++ b/subprojects/gradle-ui/src/integTest/groovy/org/gradle/integtests/LiveOutputIntegrationTest.groovy
@@ -83,7 +83,7 @@ that's likely to change over time. This version executes the command via GradleP
         TestExecutionInteraction executionInteraction = new TestExecutionInteraction();
 
         //execute a command. We don't really care what the command is, just something that generates output
-        TestUtility.executeBlocking( gradlePluginLord, "tasks", "Test Execution", executionInteraction, 80 )
+        TestUtility.executeBlocking( gradlePluginLord, "tasks", "Test Execution", executionInteraction, 100 )
 
         verifyLiveOutputObtained( executionInteraction );
     }
@@ -112,7 +112,7 @@ that's likely to change over time. This version executes the command via GradleR
                                             org.gradle.StartParameter.ShowStacktrace.INTERNAL_EXCEPTIONS,
                                             executionInteraction);
 
-        executionInteraction.waitForCompletion(80, TimeUnit.SECONDS)
+        executionInteraction.waitForCompletion(100, TimeUnit.SECONDS)
 
         verifyLiveOutputObtained( executionInteraction );
     }
diff --git a/subprojects/gradle-ui/src/test/groovy/org/gradle/foundation/TestUtility.java b/subprojects/gradle-ui/src/test/groovy/org/gradle/foundation/TestUtility.java
index 96b1512..f2c6647 100644
--- a/subprojects/gradle-ui/src/test/groovy/org/gradle/foundation/TestUtility.java
+++ b/subprojects/gradle-ui/src/test/groovy/org/gradle/foundation/TestUtility.java
@@ -35,7 +35,6 @@ import java.io.File;
 import java.util.*;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Utility class for initializing various test objects related.
@@ -392,7 +391,7 @@ public class TestUtility {
     public static void executeBlocking(GradlePluginLord gradlePluginLord, String fullCommandLine, String displayName, final ExecuteGradleCommandServerProtocol.ExecutionInteraction executionInteraction, int maximumWaitSeconds) {
         gradlePluginLord.startExecutionQueue();   //make sure its started
 
-        final AtomicBoolean isComplete = new AtomicBoolean();
+        final CountDownLatch complete = new CountDownLatch(1);
 
         GradlePluginLord.RequestObserver observer = new GradlePluginLord.RequestObserver() {
            public void executionRequestAdded( ExecutionRequest request )
@@ -403,7 +402,7 @@ public class TestUtility {
            public void aboutToExecuteRequest( Request request ) { }
 
            public void requestExecutionComplete( Request request, int result, String output ) {
-               isComplete.set(true);
+               complete.countDown();
            }
         };
 
@@ -414,21 +413,16 @@ public class TestUtility {
         Assert.assertNotNull(request);
 
         //now sleep until we're complete, but bail if we wait too long
-        int totalWaitTime = 0;
-        while (!isComplete.get() && totalWaitTime <= maximumWaitSeconds) {
-            try {
-                Thread.sleep(1000);
-            }
-            catch (InterruptedException e) {
-                e.printStackTrace();
-            }
-
-            totalWaitTime += 1;
+        boolean timeout;
+        try {
+            timeout = !complete.await(maximumWaitSeconds, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            throw UncheckedException.asUncheckedException(e);
         }
 
         gradlePluginLord.removeRequestObserver( observer );
 
-        if (!isComplete.get()) //its still running. Something is wrong.
+        if (timeout) //its still running. Something is wrong.
         {
             request.cancel(); //just to clean up after ourselves a little, cancel the request.
             throw new AssertionFailedError("Failed to comlete execution in alotted time: " + maximumWaitSeconds + " seconds. Considering this failed.");
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
index 0b84100..0de9662 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
@@ -18,23 +18,31 @@ package org.gradle.api.tasks.wrapper;
 
 import org.gradle.api.DefaultTask;
 import org.gradle.api.GradleException;
+import org.gradle.api.internal.file.FileResolver;
 import org.gradle.api.tasks.Input;
+import org.gradle.api.tasks.OutputFile;
 import org.gradle.api.tasks.TaskAction;
 import org.gradle.api.tasks.wrapper.internal.WrapperScriptGenerator;
+import org.gradle.util.DeprecationLogger;
 import org.gradle.util.GFileUtils;
 import org.gradle.util.GUtil;
+import org.gradle.util.GradleVersion;
 
 import java.io.File;
 import java.net.URL;
 import java.util.Properties;
 
 /**
- * Generates scripts (for *nix and windows) which enable to build your project with Gradle, without having to install Gradle.
- * The scripts generated by this task are supposed to be committed to your version control system. This tasks also copies
- * a gradle-wrapper.jar to your project dir which needs also be committed into your VCS.
- * The scripts delegates to this jar. If a user execute a wrapper script the first time, the script downloads the gradle-distribution and
- * runs the build against the downloaded distribution. Any installed Gradle distribution is ignored when using the wrapper scripts.
- * Alternatively you can store the distribution for the wrapper in your version control system.
+ * <p>Generates scripts (for *nix and windows) which allow you to build your project with Gradle, without having to
+ * install Gradle.
+ *
+ * <p>When a user executes a wrapper script the first time, the script downloads and installs the appropriate Gradle
+ * distribution and runs the build against this downloaded distribution. Any installed Gradle distribution is ignored
+ * when using the wrapper scripts.
+ *
+ * <p>The scripts generated by this task are intended to be committed to your version control system. This task also
+ * generates a small {@code gradle-wrapper.jar} bootstrap JAR file and properties file which should also be committed to
+ * your VCS. The scripts delegates to this JAR.
  *
  * @author Hans Dockter
  */
@@ -51,7 +59,7 @@ public class Wrapper extends DefaultTask {
     static final String WRAPPER_DIR = "gradle-wrapper";
     static final String WRAPPER_JAR = WRAPPER_DIR + ".jar";
     static final String WRAPPER_PROPERTIES = WRAPPER_DIR + ".properties";
-    
+
     public static final String DEFAULT_URL_ROOT = "http://dist.codehaus.org/gradle";
     public static final String WRAPPER_JAR_BASE_NAME = "gradle-wrapper";
     public static final String DEFAULT_DISTRIBUTION_PARENT_NAME = "wrapper/dists";
@@ -61,13 +69,12 @@ public class Wrapper extends DefaultTask {
     /**
      * Specifies how the wrapper path should be interpreted.
      */
-    public enum PathBase { PROJECT, GRADLE_USER_HOME }
-
-    @Input
-    private String scriptDestinationPath;
+    public enum PathBase {
+        PROJECT, GRADLE_USER_HOME
+    }
 
-    @Input
-    private String jarPath;
+    private Object scriptFile;
+    private Object jarFile;
 
     @Input
     private String distributionPath;
@@ -78,7 +85,7 @@ public class Wrapper extends DefaultTask {
     @Input
     private String archiveClassifier;
 
-    @Input
+    //    @Input
     private PathBase distributionBase = PathBase.GRADLE_USER_HOME;
 
     @Input
@@ -90,39 +97,45 @@ public class Wrapper extends DefaultTask {
     @Input
     private String archivePath;
 
-    @Input
+    //    @Input
     private PathBase archiveBase = PathBase.GRADLE_USER_HOME;
 
     private WrapperScriptGenerator wrapperScriptGenerator = new WrapperScriptGenerator();
 
     public Wrapper() {
-        scriptDestinationPath = "";
-        jarPath = "";
+        scriptFile = "gradlew";
+        jarFile = "gradle/wrapper/gradle-wrapper.jar";
         distributionPath = DEFAULT_DISTRIBUTION_PARENT_NAME;
         archiveName = DEFAULT_ARCHIVE_NAME;
         archiveClassifier = DEFAULT_ARCHIVE_CLASSIFIER;
         archivePath = DEFAULT_DISTRIBUTION_PARENT_NAME;
         urlRoot = DEFAULT_URL_ROOT;
+        gradleVersion = new GradleVersion().getVersion();
     }
 
     @TaskAction
     void generate() {
-        String wrapperDir = GUtil.isTrue(jarPath) ? jarPath + "/" : "";
-        new File(getProject().getProjectDir(), wrapperDir).mkdirs();
-        String wrapperJar = wrapperDir + WRAPPER_JAR;
-        String wrapperPropertiesPath = wrapperDir + WRAPPER_PROPERTIES;
-        File jarFileDestination = new File(getProject().getProjectDir(), wrapperJar);
-        File propertiesFileDestination = new File(getProject().getProjectDir(), wrapperPropertiesPath);
+        File jarFileDestination = getJarFile();
+        File propertiesFileDestination = getPropertiesFile();
+        File scriptFileDestination = getScriptFile();
+        FileResolver resolver = getServices().get(FileResolver.class).withBaseDir(
+                scriptFileDestination.getParentFile());
+        String jarFileRelativePath = resolver.resolveAsRelativePath(jarFileDestination);
+        String propertiesFileRelativePath = resolver.resolveAsRelativePath(propertiesFileDestination);
+
+        propertiesFileDestination.delete();
+        jarFileDestination.delete();
+        scriptFileDestination.delete();
+
+        writeProperties(propertiesFileDestination);
+
         URL jarFileSource = getClass().getResource("/" + WRAPPER_JAR_BASE_NAME + ".jar");
         if (jarFileSource == null) {
             throw new GradleException("Cannot locate wrapper JAR resource.");
         }
-        propertiesFileDestination.delete();
-        jarFileDestination.delete();
-        writeProperties(propertiesFileDestination);
         GFileUtils.copyURLToFile(jarFileSource, jarFileDestination);
-        File scriptDestinationDir = new File(getProject().getProjectDir(), scriptDestinationPath);
-        wrapperScriptGenerator.generate(wrapperJar, wrapperPropertiesPath, scriptDestinationDir);
+
+        wrapperScriptGenerator.generate(jarFileRelativePath, propertiesFileRelativePath, scriptFileDestination);
     }
 
     private void writeProperties(File propertiesFileDestination) {
@@ -139,60 +152,101 @@ public class Wrapper extends DefaultTask {
     }
 
     /**
-     * Returns the script destination path.
+     * Returns the file to write the wrapper script to.
+     */
+    @OutputFile
+    public File getScriptFile() {
+        return getProject().file(scriptFile);
+    }
+
+    public void setScriptFile(Object scriptFile) {
+        this.scriptFile = scriptFile;
+    }
+
+    /**
+     * Returns the script destination path, relative to the project directory.
      *
-     * @see #setScriptDestinationPath(String) 
+     * @see #setScriptDestinationPath(String)
      */
+    @Deprecated
     public String getScriptDestinationPath() {
-        return scriptDestinationPath;
+        DeprecationLogger.nagUser("getScriptDestinationPath()", "getScriptFile()");
+        return getProject().relativePath(getScriptFile().getParentFile());
     }
 
     /**
-     * Specifies a path as the parent dir of the scripts which are generated when executing the wrapper task.
-     * This path specifies a directory <i>relative</i> to the project dir.  Defaults to empty string, i.e. the scripts
-     * are placed into the project root dir.
+     * Specifies a path as the parent dir of the scripts which are generated when executing the wrapper task. This path
+     * specifies a directory <i>relative</i> to the project dir.  Defaults to empty string, i.e. the scripts are placed
+     * into the project root dir.
      *
-     * @param scriptDestinationPath Any object which <code>toString</code> method specifies the path.
-     * Most likely a String or File object.
+     * @param scriptDestinationPath Any object which <code>toString</code> method specifies the path. Most likely a
+     * String or File object.
      */
+    @Deprecated
     public void setScriptDestinationPath(String scriptDestinationPath) {
-        this.scriptDestinationPath = scriptDestinationPath;
+        DeprecationLogger.nagUser("setScriptDestinationPath()", "setScriptFile()");
+        setScriptFile(scriptDestinationPath + "/gradlew");
+    }
+
+    /**
+     * Returns the file to write the wrapper jar file to.
+     */
+    @OutputFile
+    public File getJarFile() {
+        return getProject().file(jarFile);
+    }
+
+    public void setJarFile(Object jarFile) {
+        this.jarFile = jarFile;
     }
 
     /**
-     * Returns the jar path.
+     * Returns the file to write the wrapper properties to.
+     */
+    @OutputFile
+    public File getPropertiesFile() {
+        File jarFileDestination = getJarFile();
+        return new File(jarFileDestination.getParentFile(), jarFileDestination.getName().replaceAll("\\.jar$",
+                ".properties"));
+    }
+
+    /**
+     * Returns the jar path, relative to the project directory.
      *
-     * @see #setJarPath(String) 
+     * @see #setJarPath(String)
      */
+    @Deprecated
     public String getJarPath() {
-        return jarPath.toString();
+        DeprecationLogger.nagUser("getJarPath()", "getJarFile()");
+        return getProject().relativePath(getJarFile().getParentFile());
     }
 
     /**
      * When executing the wrapper task, the jar path specifies the path where the gradle-wrapper.jar is copied to. The
      * jar path must be a path relative to the project dir. The gradle-wrapper.jar must be submitted to your version
      * control system. Defaults to empty string, i.e. the jar is placed into the project root dir.
-     *
-     * @param jarPath
      */
+    @Deprecated
     public void setJarPath(String jarPath) {
-        this.jarPath = jarPath;
+        DeprecationLogger.nagUser("setJarPath()", "setJarFile()");
+        setJarFile(jarPath + "/gradle-wrapper.jar");
     }
 
     /**
-     * Returns the distribution path.
+     * Returns the path where the gradle distributions needed by the wrapper are unzipped. The path is relative to the
+     * distribution base directory
      *
-     * @see #setDistributionPath(String) 
+     * @see #setDistributionPath(String)
      */
     public String getDistributionPath() {
         return distributionPath;
     }
 
     /**
-     * Set's the path where the gradle distributions needed by the wrapper are unzipped. The path is relative to the
-     * dir specified with {@link #distributionBase}.
+     * Sets the path where the gradle distributions needed by the wrapper are unzipped. The path is relative to the
+     * distribution base directory
      *
-     * @param distributionPath  
+     * @see #setDistributionPath(String)
      */
     public void setDistributionPath(String distributionPath) {
         this.distributionPath = distributionPath;
@@ -201,46 +255,44 @@ public class Wrapper extends DefaultTask {
     /**
      * Returns the gradle version for the wrapper.
      *
-     * @see #setGradleVersion(String) 
+     * @see #setGradleVersion(String)
      */
     public String getGradleVersion() {
         return gradleVersion;
     }
 
     /**
-     * The version of the gradle distribution required by the wrapper. This is usually the same version of Gradle you use
-     * for building your project.
-     *
-     * @param gradleVersion
+     * The version of the gradle distribution required by the wrapper. This is usually the same version of Gradle you
+     * use for building your project.
      */
     public void setGradleVersion(String gradleVersion) {
         this.gradleVersion = gradleVersion;
     }
 
+    /**
+     * The base URL to download the gradle distribution from.
+     *
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
+     *
+     * <p>The wrapper downloads a certain distribution only once and caches it. If your distribution base is the
+     * project, you might submit the distribution to your version control system. That way no download is necessary at
+     * all. This might be in particular interesting, if you provide a custom gradle snapshot to the wrapper, because you
+     * don't need to provide a download server then.
+     */
     public String getUrlRoot() {
         return urlRoot;
     }
 
     /**
-     * A URL where to download the gradle distribution from. The pattern used by the wrapper for downloading is:
-     * <code>{@link #getUrlRoot()}/{@link #getArchiveName()}-{@link #getArchiveClassifier()}-{@link #getGradleVersion()}.zip</code>.
-     * The default for the URL root is {@link #DEFAULT_URL_ROOT}.
-     *
-     * The wrapper downloads a certain distribution only ones and caches it.
-     * If your {@link #getDistributionBase()} is the project, you might submit the distribution to your version control system.
-     * That way no download is necessary at all. This might be in particular interesting, if you provide a custom gradle snapshot to the wrapper,
-     * because you don't need to provide a download server then.
-     *  
-     * @param urlRoot
+     * Sets the base URL to download the gradle distribution from.
      */
     public void setUrlRoot(String urlRoot) {
         this.urlRoot = urlRoot;
     }
 
     /**
-     * Returns the distribution base.
-     *
-     * @see #setDistributionBase(org.gradle.api.tasks.wrapper.Wrapper.PathBase) 
+     * The distribution base specifies whether the unpacked wrapper distribution should be stored in the project or in
+     * the gradle user home dir.
      */
     public PathBase getDistributionBase() {
         return distributionBase;
@@ -248,93 +300,70 @@ public class Wrapper extends DefaultTask {
 
     /**
      * The distribution base specifies whether the unpacked wrapper distribution should be stored in the project or in
-     * the gradle user home dir. The path specified in {@link #distributionPath} is a relative path to either of those
-     * dirs.  
-     *
-     * @param distributionBase
+     * the gradle user home dir.
      */
     public void setDistributionBase(PathBase distributionBase) {
         this.distributionBase = distributionBase;
     }
 
     /**
-     * Returns the archive path.
-     *
-     * @see #setArchivePath(String) 
+     * Returns the path where the gradle distributions archive should be saved (i.e. the parent dir). The path is
+     * relative to the archive base directory.
      */
     public String getArchivePath() {
         return archivePath;
     }
 
     /**
-     * Set's the path where the gradle distributions archive should be saved (i.e. the parent dir). The path is relative to the
-     * parent dir specified with {@link #getArchiveBase()}.
-     *
-     * @param archivePath
+     * Set's the path where the gradle distributions archive should be saved (i.e. the parent dir). The path is relative
+     * to the parent dir specified with {@link #getArchiveBase()}.
      */
     public void setArchivePath(String archivePath) {
         this.archivePath = archivePath;
     }
 
     /**
-     * Returns the archive base.
-     *
-     * @see #setArchiveBase(org.gradle.api.tasks.wrapper.Wrapper.PathBase) 
+     * The archive base specifies whether the unpacked wrapper distribution should be stored in the project or in the
+     * gradle user home dir.
      */
     public PathBase getArchiveBase() {
         return archiveBase;
     }
 
     /**
-     * The distribution base specifies whether the unpacked wrapper distribution should be stored in the project or in
-     * the gradle user home dir. The path specified in {@link #getArchivePath()} is a relative path to etiher of those dirs.
-     *
-     * @param archiveBase
+     * The archive base specifies whether the unpacked wrapper distribution should be stored in the project or in the
+     * gradle user home dir.
      */
     public void setArchiveBase(PathBase archiveBase) {
         this.archiveBase = archiveBase;
     }
 
     /**
-     * Returnes the archive name.
+     * The name of the archive as part of the download URL.
+     *
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
      *
-     * @see #setArchiveName(String) 
+     * <p>The default for the archive name is {@value #DEFAULT_ARCHIVE_NAME}.
      */
     public String getArchiveName() {
         return archiveName;
     }
 
-    /**
-     * Specifies the name of the archive as part of the download URL. The download URL is assembled by the pattern:
-     *
-     * <code>{@link #getUrlRoot()}/{@link #getArchiveName()}-{@link #getArchiveClassifier()}-{@link #getGradleVersion()}.zip</code>
-     *
-     * The default for the archive name is {@link #DEFAULT_ARCHIVE_NAME}.
-     *
-     * @param archiveName
-     */
     public void setArchiveName(String archiveName) {
         this.archiveName = archiveName;
     }
 
     /**
-     * Returns the archive classifier.
+     * The classifier of the archive as part of the download URL.
+     *
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
      *
-     * @see #setArchiveClassifier(String) 
+     * <p>The default for the archive classifier is {@value #DEFAULT_ARCHIVE_CLASSIFIER}.
      */
     public String getArchiveClassifier() {
         return archiveClassifier;
     }
 
-    /**
-     * Specifies the classifier of the archive as part of the download URL. The download URL is assembled by the pattern:
-     *
-     * <code>{@link #getUrlRoot()}/{@link #getArchiveName()}-{@link #getArchiveClassifier()}-{@link #getGradleVersion()}.zip</code>
-     *
-     * The default for the archive classifier is {@link #DEFAULT_ARCHIVE_CLASSIFIER}.
-     *
-     * @param archiveClassifier
-     */
     public void setArchiveClassifier(String archiveClassifier) {
         this.archiveClassifier = archiveClassifier;
     }
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/WrapperScriptGenerator.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/WrapperScriptGenerator.java
index 3fb0e25..041935a 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/WrapperScriptGenerator.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/WrapperScriptGenerator.java
@@ -37,16 +37,16 @@ public class WrapperScriptGenerator {
     public static final String CURRENT_DIR_WINDOWS = "%DIRNAME%";
     private static final String FULLY_QUALIFIED_WRAPPER_NAME = "org.gradle.wrapper.GradleWrapperMain";
 
-    public void generate(String jarPath, String wrapperPropertiesPath, File scriptDestinationDir) {
+    public void generate(String jarPath, String wrapperPropertiesPath, File scriptFile) {
         try {
-            createUnixScript(jarPath, scriptDestinationDir, wrapperPropertiesPath);
-            createWindowsScript(jarPath, scriptDestinationDir, wrapperPropertiesPath);
+            createUnixScript(jarPath, scriptFile, wrapperPropertiesPath);
+            createWindowsScript(jarPath, scriptFile, wrapperPropertiesPath);
         } catch (IOException e) {
             throw new UncheckedIOException(e);
         }
     }
 
-    private void createUnixScript(String jarPath, File scriptDestinationDir, String wrapperPropertiesPath) throws IOException {
+    private void createUnixScript(String jarPath, File scriptFile, String wrapperPropertiesPath) throws IOException {
         String unixWrapperScriptHead = IOUtils.toString(getClass().getResourceAsStream("unixWrapperScriptHead.txt"));
         String unixWrapperScriptTail = IOUtils.toString(getClass().getResourceAsStream("unixWrapperScriptTail.txt"));
 
@@ -56,7 +56,7 @@ public class WrapperScriptGenerator {
                 "WRAPPER_PROPERTIES=" + CURRENT_DIR_UNIX + "/" + FilenameUtils.separatorsToUnix(wrapperPropertiesPath) + UNIX_NL;
 
         String unixScript = unixWrapperScriptHead + fillingUnix + unixWrapperScriptTail;
-        File unixScriptFile = new File(scriptDestinationDir, "gradlew");
+        File unixScriptFile = scriptFile;
         FileUtils.writeStringToFile(unixScriptFile, unixScript);
         createExecutablePermission(unixScriptFile);
     }
@@ -69,7 +69,7 @@ public class WrapperScriptGenerator {
         chmod.execute();
     }
 
-    private void createWindowsScript(String jarPath, File scriptDestinationDir, String wrapperPropertiesPath) throws IOException {
+    private void createWindowsScript(String jarPath, File scriptFile, String wrapperPropertiesPath) throws IOException {
         String windowsWrapperScriptHead = IOUtils.toString(getClass().getResourceAsStream("windowsWrapperScriptHead.txt"));
         String windowsWrapperScriptTail = IOUtils.toString(getClass().getResourceAsStream("windowsWrapperScriptTail.txt"));
         String fillingWindows = "" + WINDOWS_NL +
@@ -77,7 +77,7 @@ public class WrapperScriptGenerator {
                 "set CLASSPATH=" + CURRENT_DIR_WINDOWS + "\\" + FilenameUtils.separatorsToWindows(jarPath) + WINDOWS_NL +
                 "set WRAPPER_PROPERTIES=" + CURRENT_DIR_WINDOWS + "\\" + FilenameUtils.separatorsToWindows(wrapperPropertiesPath) + WINDOWS_NL;
         String windowsScript = windowsWrapperScriptHead + fillingWindows + windowsWrapperScriptTail;
-        File windowsScriptFile = new File(scriptDestinationDir, "gradlew.bat");
+        File windowsScriptFile = new File(scriptFile.getParentFile(), scriptFile.getName() + ".bat");
         FileUtils.writeStringToFile(windowsScriptFile, transformIntoWindowsNewLines(windowsScript));
     }
 
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
index b167da3..7b201e2 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
@@ -19,10 +19,7 @@ package org.gradle.api.tasks.wrapper;
 import org.gradle.api.internal.AbstractTask;
 import org.gradle.api.tasks.AbstractTaskTest;
 import org.gradle.api.tasks.wrapper.internal.WrapperScriptGenerator;
-import org.gradle.util.GUtil;
-import org.gradle.util.TemporaryFolder;
-import org.gradle.util.TestFile;
-import org.gradle.util.WrapUtil;
+import org.gradle.util.*;
 import org.gradle.wrapper.GradleWrapperMain;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
@@ -44,12 +41,9 @@ import static org.junit.Assert.*;
  */
 @RunWith(org.jmock.integration.junit4.JMock.class)
 public class WrapperTest extends AbstractTaskTest {
-    public static final String TEST_TEXT = "sometext";
-    public static final String TEST_FILE_NAME = "somefile";
 
     private Wrapper wrapper;
     private WrapperScriptGenerator wrapperScriptGeneratorMock;
-    private String distributionPath;
     private String targetWrapperJarPath;
     private Mockery context = new Mockery();
     private TestFile expectedTargetWrapperJar;
@@ -71,9 +65,8 @@ public class WrapperTest extends AbstractTaskTest {
         expectedTargetWrapperProperties = new File(getProject().getProjectDir(),
                 targetWrapperJarPath + "/" + Wrapper.WRAPPER_PROPERTIES);
         new File(getProject().getProjectDir(), targetWrapperJarPath).mkdirs();
-        distributionPath = "somepath";
         wrapper.setJarPath(targetWrapperJarPath);
-        wrapper.setDistributionPath(distributionPath);
+        wrapper.setDistributionPath("somepath");
         wrapper.setUnixWrapperScriptGenerator(wrapperScriptGeneratorMock);
     }
 
@@ -82,10 +75,13 @@ public class WrapperTest extends AbstractTaskTest {
     }
 
     @Test
-    public void testWrapper() {
+    public void testWrapperDefaults() {
         wrapper = createTask(Wrapper.class);
-        assertEquals("", wrapper.getJarPath());
-        assertEquals("", wrapper.getScriptDestinationPath());
+        assertEquals(new File(getProject().getProjectDir(), "gradle/wrapper/gradle-wrapper.jar"), wrapper.getJarFile());
+        assertEquals(toNative("gradle/wrapper"), wrapper.getJarPath());
+        assertEquals(new File(getProject().getProjectDir(), "gradlew"), wrapper.getScriptFile());
+        assertEquals(".", wrapper.getScriptDestinationPath());
+        assertEquals(new GradleVersion().getVersion(), wrapper.getGradleVersion());
         assertEquals(Wrapper.DEFAULT_DISTRIBUTION_PARENT_NAME, wrapper.getDistributionPath());
         assertEquals(Wrapper.DEFAULT_ARCHIVE_NAME, wrapper.getArchiveName());
         assertEquals(Wrapper.DEFAULT_ARCHIVE_CLASSIFIER, wrapper.getArchiveClassifier());
@@ -103,8 +99,7 @@ public class WrapperTest extends AbstractTaskTest {
     @Test
     public void testCheckInputs() throws IOException {
         assertThat(wrapper.getInputs().getProperties().keySet(),
-                equalTo(WrapUtil.toSet("jarPath", "archiveClassifier", "distributionBase", "archiveBase",
-                        "distributionPath", "archiveName", "urlRoot", "scriptDestinationPath", "gradleVersion", "archivePath")));
+                equalTo(WrapUtil.toSet("archiveClassifier", "distributionPath", "archiveName", "urlRoot", "gradleVersion", "archivePath")));
     }
 
     @Test
@@ -126,9 +121,9 @@ public class WrapperTest extends AbstractTaskTest {
         context.checking(new Expectations() {
             {
                 one(wrapperScriptGeneratorMock).generate(
-                        targetWrapperJarPath + "/" + Wrapper.WRAPPER_JAR,
-                        targetWrapperJarPath + "/" + Wrapper.WRAPPER_PROPERTIES,
-                        new File(getProject().getProjectDir(), wrapper.getScriptDestinationPath()));
+                        toNative("../" + targetWrapperJarPath + "/" + Wrapper.WRAPPER_JAR),
+                        toNative("../" + targetWrapperJarPath + "/" + Wrapper.WRAPPER_PROPERTIES),
+                        wrapper.getScriptFile());
             }
         });
         wrapper.execute();
@@ -145,4 +140,8 @@ public class WrapperTest extends AbstractTaskTest {
         assertEquals(properties.getProperty(Wrapper.ZIP_STORE_BASE_PROPERTY), wrapper.getArchiveBase().toString());
         assertEquals(properties.getProperty(Wrapper.ZIP_STORE_PATH_PROPERTY), wrapper.getArchivePath());
     }
+
+    private String toNative(String s) {
+        return s.replace("/", File.separator);
+    }
 }
\ No newline at end of file
diff --git a/wrapper/gradle-wrapper.properties b/wrapper/gradle-wrapper.properties
index 285ab11..6ebe28f 100644
--- a/wrapper/gradle-wrapper.properties
+++ b/wrapper/gradle-wrapper.properties
@@ -18,7 +18,7 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
-distributionVersion=0.9-rc-2
+distributionVersion=0.9-rc-3
 zipStorePath=wrapper/dists
 urlRoot=http\://dist.codehaus.org/gradle
 distributionName=gradle

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/gradle-1.12.git



More information about the pkg-java-commits mailing list