<!--
  ~ Copyright 2009 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.
  -->
<chapter id='plugins'>
    <title>Gradle Plugins</title>
    <para>
        Gradle at its core intentionally provides very little for real world automation. All of the useful
        features, like the ability to compile Java code, are added by <emphasis>plugins</emphasis>.
        Plugins add new tasks (e.g. <apilink class='org.gradle.api.tasks.compile.JavaCompile'/>), domain objects (e.g.
        <apilink class="org.gradle.api.tasks.SourceSet"/>), conventions (e.g. Java source is located at
        <literal>src/main/java</literal>) as well as extending core objects and objects from other plugins.
    </para>
    <para>
        In this chapter we will discuss how to use plugins and the terminology and concepts surrounding plugins.
    </para>
    <section id="sec:types_of_plugins">
        <title>Types of plugins</title>
        <para>
            There are two general types of plugins in Gradle, <emphasis>script</emphasis> plugins and <emphasis>binary</emphasis> plugins.
            Script plugins are additional build scripts that further configure the build and usually implement a declarative approach to
            manipulating the build.  They are typically used within a build although they can be externalized and accessed from a remote
            location.  Binary plugins are classes that implement the <apilink class='org.gradle.api.Plugin'/> interface and adopt a programmatic
            approach to manipulating the build.  Binary plugins can reside within a build script, within the project hierarchy or externally
            in a plugin jar.
        </para>
    </section>
    <section id='sec:using_plugins'>
        <title>Applying plugins</title>
        <para>
            Plugins are said to be <emphasis>applied</emphasis>, which is done via the <apilink class="org.gradle.api.Project" method="apply(java.util.Map)" /> method.
        </para>
        <section>
            <title>Script plugins</title>
            <sample id="configureProjectUsingScript" dir="userguide/tutorial/configureProjectUsingScript" title="Applying a script plugin">
                <sourcefile file="build.gradle"/>
            </sample>
            <para>
                Script plugins can be applied from a script on the local filesystem or at a remote location.  Filesystem
                locations are relative to the project directory, while remote script locations are specified with an HTTP URL.
                Multiple script plugins (of either form) can be applied to a given build.
            </para>
        </section>
        <section>
            <title>Binary plugins</title>
            <sample id="useJavaPlugin" dir="java/quickstart" title="Applying a binary plugin">
                <sourcefile file="build.gradle" snippet="use-plugin"/>
            </sample>
            <para>
                Core plugins register a short name. In the above case, we are using the short name
                ‘<literal>java</literal>’ to apply the <apilink class="org.gradle.api.plugins.JavaPlugin" />.
                Plugins also have a <emphasis>plugin id</emphasis> that takes a fully qualified
                form like <literal>com.github.foo.bar</literal>, although some legacy plugins may still utilize
                the short, unqualified form.
            </para>
            <para>
                This method can also accept a class to identify the plugin:
            </para>
            <sample id="pluginIntro" dir="userguide/tutorial/pluginIntro" title="Applying a binary plugin by type">
                <sourcefile file="build.gradle" snippet="apply-by-type"/>
            </sample>
            <para>
                The <literal>JavaPlugin</literal> symbol in the above sample refers to the the <apilink class="org.gradle.api.plugins.JavaPlugin"/>.
                This class does not strictly need to be import as the <literal>org.gradle.api.plugins</literal> package is automatically imported in all build scripts
                (see <xref linkend='ide_support'/>). Furthermore, it is not necessary to append <literal>.class</literal> to identify a class literal in Groovy as it is in Java.
            </para>
            <para>
                The application of plugins is <emphasis>idempotent</emphasis>. That is, a plugin can be applied multiple times. If the plugin
                has previously been applied, any further applications will have no effect.
            </para>
            <section>
                <title>Locations of binary plugins</title>
                <para>
                    A plugin is simply any class that implements the <apilink class="org.gradle.api.Plugin" /> interface. Gradle provides
                    the core plugins as part of its distribution so simply applying the plugin as above is all you need to do.
                    However, non-core binary plugins need to be available to the build classpath before they can be applied.  This can
                    be achieved in a number of ways, including:
                </para>
                <itemizedlist>
                    <listitem>Defining the plugin as an inline class declaration inside a build script.</listitem>
                    <listitem>Defining the plugin as a source file under the buildSrc directory in the project.</listitem>
                    <listitem>Including the plugin from an external jar defined as a buildscript dependency (see <xref linkend="sec:external_dependencies" />).</listitem>
                    <listitem>Including the plugin from the plugin portal using the plugins DSL (see <xref linkend="sec:plugins_block" />).</listitem>
                </itemizedlist>
                <para>
                    For more on defining your own plugins, see <xref linkend="custom_plugins" />.
                </para>
            </section>
        </section>
    </section>
    <section id="sec:plugins_block">
        <title>Applying plugins with the plugins DSL</title>
        <note>
            <para>
                The plugins DSL is currently <link linkend="feature_lifecycle">incubating</link>.
                Please be aware that the DSL and other configuration may change in later Gradle versions.
            </para>
        </note>
        <para>
            The new plugins DSL provides a more succinct and convenient way to declare plugin dependencies.  It works with the
            new <ulink url="http://plugins.gradle.org">Gradle plugin portal</ulink> to provide easy access to both core and community
            plugins.  The plugins script block configures an instance of <apilink class="org.gradle.plugin.use.PluginDependenciesSpec" />.
        </para>
        <para>
            To apply a core plugin, the short name can be used:
        </para>
        <sample id="useJavaPluginDSL" dir="plugin-dsl" title="Applying a core plugin">
            <sourcefile file="build.gradle" snippet="use-plugin"/>
        </sample>
        <para>
            To apply a community plugin from the portal, the fully qualified plugin id must be used:
        </para>
        <sample id="useCommunityPluginDSL" dir="plugin-dsl" title="Applying a community plugin">
            <sourcefile file="build.gradle" snippet="use-community-plugin"/>
        </sample>
        <para>
            No further configuration is necessary.  Specifically, there is no need to configure the buildscript classpath.
            Gradle will resolve the plugin in the plugin portal, locate it, and make it available to the build.
        </para>
        <para>
            See <apilink class="org.gradle.plugin.use.PluginDependenciesSpec" /> for more information on using the Plugin DSL.
        </para>
    </section>
    <section>
        <title>Finding community plugins</title>
        <para>
            Gradle has a vibrant community of plugin developers who contribute plugins for a wide variety of capabilities.
            The Gradle <ulink url="http://plugins.gradle.org">plugin portal</ulink> provides an interface for searching and
            exploring community plugins.
        </para>
    </section>
    <section>
        <title>What plugins do</title>
        <para>
            Applying a plugin to the project allows the plugin to extend the project's capabilities. It can do things
            such as:
        </para>
        <itemizedlist>
            <listitem>Add tasks to the project (e.g. compile, test)</listitem>
            <listitem>Pre-configure added tasks with useful defaults.</listitem>
            <listitem>Add dependency configurations to the project (see <xref linkend="configurations"/>).</listitem>
            <listitem>Add new properties and methods to existing type via extensions.</listitem>
        </itemizedlist>
        <para>
            Let's check this out:
        </para>
        <sample id="pluginIntro" dir="userguide/tutorial/pluginIntro" title="Tasks added by a plugin">
            <sourcefile file="build.gradle" snippet="apply-by-id"/>
            <output args="-q show"/>
        </sample>
        <para>
            The Java plugin has added a <literal>compileJava</literal> task and a <literal>processResources</literal> task
            to the project and configured the <literal>destinationDir</literal> property of both of these tasks.
        </para>
    </section>
    <section id='sub:more_about_convention_objects'>
        <title>Conventions</title>
        <para>
            Plugins can pre-configure the project in smart ways to support convention-over-configuration. Gradle
            provides mechanisms and sophisticated support and it's a key ingredient in powerful-yet-concise build scripts.
        </para>
        <para>
            We saw in the example above that the Java plugins adds a task named <literal>compileJava</literal> that has
            a property named <literal>destinationDir</literal> (that configures where the compiled Java source should be placed).
            The Java plugin defaults this property to point to <literal>build/classes/main</literal> in the project directory.
            This is an example of convention-over-configuration via a <emphasis>reasonable default</emphasis>.
        </para>
        <para>
            We can change this property simply by giving it a new value.
        </para>
        <sample id="pluginConfig" dir="userguide/tutorial/pluginConfig" title="Changing plugin defaults">
            <sourcefile file="build.gradle"/>
            <output args="-q show"/>
        </sample>
        <para>
            However, it's likely that the <literal>compileJava</literal> task is not the only task that needs to know where
            the class files are. 
        </para>
        <para>
            The Java plugin adds the concept of <emphasis>source sets</emphasis> (see <apilink class="org.gradle.api.tasks.SourceSet" />)
            to describe the aspects of a set of source files, one aspect being where the class files should be written to when they are compiled.
            The Java plugin maps the <literal>destinationDir</literal> property of the <literal>compileJava</literal> task to this aspect of the source set.
        </para>
        <para>
            We can change where the class files are written to by configuring the source set.
        </para>
        <sample id="pluginConvention" dir="userguide/tutorial/pluginConvention" title="Plugin convention object">
            <sourcefile file="build.gradle"/>
            <output args="-q show"/>
        </sample>
        <para>
            In the example above, we applied the Java plugin which, among other things, did the following:
        </para>
        <itemizedlist>
            <listitem>Added a new domain object type: <apilink class="org.gradle.api.tasks.SourceSet" /></listitem>
            <listitem>Configured a <literal>main</literal> source set with default (i.e. conventional) values for properties</listitem>
            <listitem>Configured supporting tasks to use these properties to perform work</listitem>
        </itemizedlist>
        <para>
            All of this happened during the “<literal>apply plugin: "java"</literal>” step. In the example above, we <emphasis>changed</emphasis>
            the desired location of the class files after this conventional configuration had been performed. Notice by the output with the example
            that the value for <literal>compileJava.destinationDir</literal> also changed to reflect the configuration change.
        </para>
        <para>
            Consider the case where another task needs to consume the class files. If this task is configured to use the value from
            <literal>sourceSets.main.output.classesDir</literal>, then changing it in this location will update this
            new task in addition to the <literal>compileJava</literal> task whenever it is changed.
        </para>
        <para>
            This ability to configure properties of objects to reflect the value of another object's task at all times (i.e. even when it changes) is
            known as “<emphasis>convention mapping</emphasis>”. It allows Gradle to provide conciseness through convention-over-configuration and
            sensible defaults yet not require complete reconfiguration if a conventional default needs to be changed. Without this, in the example above,
            we would have had to reconfigure every object that needs to work with the class files.
        </para>
    </section>
    <section>
        <title>More on plugins</title>
        <para>
            This chapter aims to serve as an introduction to plugins and Gradle and the role they play. For more information on the inner workings
            of plugins, see <xref linkend="custom_plugins" />.
        </para>
    </section>
</chapter>
