001/*
002 * SonarQube
003 * Copyright (C) 2009-2017 SonarSource SA
004 * mailto:info AT sonarsource DOT com
005 *
006 * This program is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api;
021
022import javax.annotation.concurrent.Immutable;
023
024import org.sonar.api.batch.ScannerSide;
025import org.sonar.api.batch.sensor.Sensor;
026import org.sonar.api.batch.sensor.SensorContext;
027import org.sonar.api.ce.ComputeEngineSide;
028import org.sonar.api.server.ServerSide;
029import org.sonar.api.utils.Version;
030import org.sonarsource.api.sonarlint.SonarLintSide;
031
032/**
033 * Information about runtime environment.
034 *
035 * <p>
036 * A usage for plugins is to benefit from new APIs
037 * while keeping backward-compatibility with previous versions of SonarQube
038 * or SonarLint.
039 * </p>
040 *
041 * <p>
042 * Example: a plugin extension wants to use a new feature of API 6.1 without
043 * breaking compatibility with version 6.0 at runtime. This new feature
044 * would be enabled only in 6.1 and greater runtimes.
045 * </p>
046 * <pre>
047 * // Component provided by sonar-plugin-api
048 * // @since 6.0
049 * public interface AnApi {
050 *   // implicitly since 6.0
051 *   public void foo();
052 *
053 *   // @since 6.1
054 *   public void bar();
055 * }
056 * 
057 * // Plugin extension
058 * public class MyExtension {
059 *   private final SonarRuntime sonarRuntime;
060 *   private final AnApi api;
061 *
062 *   public MyExtension(SonarRuntime sonarRuntime, AnApi api) {
063 *     this.sonarRuntime = sonarRuntime;
064 *     this.api = api;
065 *   }
066 *
067 *   public void doSomething() {
068 *     // assume that minimal supported runtime is 6.0
069 *     api.foo();
070 *
071 *     if (sonarRuntime.getApiVersion().isGreaterThanOrEqual(Version.create(6, 1))) {
072 *       api.bar();
073 *     }
074 *   }
075 * }
076 * </pre>
077 *
078 *
079 * <p>
080 *   Note that {@link Sensor} extensions can directly get {@link SonarRuntime} through
081 * {@link SensorContext#runtime()}, without using constructor injection:
082 * </p>
083 * <pre>
084 * public class MySensor implements Sensor {
085 *
086 *   public void execute(SensorContext context) {
087 *     if (context.runtime().getApiVersion().isGreaterThanOrEqual(Version.create(6, 1)) {
088 *       context.newMethodIntroducedIn6_0();
089 *     }
090 *   }
091 *
092 * }
093 * </pre>
094 *
095 * <p>
096 * The minimal supported version of plugin API is verified at runtime. As plugin is built
097 * with sonar-plugin-api 6.1, we assume that the plugin requires v6.1 or greater at runtime.
098 * For this reason the plugin must override the minimal supported version
099 * in the configuration of sonar-packaging-maven-plugin 1.16+:
100 * <p>
101 * <pre>
102 * &lt;packaging&gt;sonar-plugin&lt;/packaging&gt;
103 *
104 * &lt;dependencies&gt;
105 *   &lt;dependency&gt;
106 *     &lt;groupId&gt;org.sonarsource.sonarqube&lt;/groupId&gt;
107 *     &lt;artifactId&gt;sonar-plugin-api&lt;/artifactId&gt;
108 *     &lt;version&gt;6.1&lt;/version&gt;
109 *     &lt;scope&gt;provided&lt;/scope&gt;
110 *   &lt;/dependency&gt;
111 * &lt;/dependencies&gt;
112 *
113 * &lt;build&gt;
114 *  &lt;plugins&gt;
115 *    &lt;plugin&gt;
116 *      &lt;groupId&gt;org.sonarsource.sonar-packaging-maven-plugin&lt;/groupId&gt;
117 *      &lt;artifactId&gt;sonar-packaging-maven-plugin&lt;/artifactId&gt;
118 *      &lt;version&gt;1.16&lt;/version&gt;
119 *      &lt;extensions&gt;true&lt;/extensions&gt;
120 *      &lt;configuration&gt;
121 *        &lt;!-- Override the default value 6.0 which is guessed from sonar-plugin-api dependency --&gt;
122 *        &lt;sonarQubeMinVersion&gt;6.0&lt;/sonarQubeMinVersion&gt;
123 *      &lt;/configuration&gt;
124 *    &lt;/plugin&gt;
125 *  &lt;/plugins&gt;
126 * &lt;/build&gt;
127 * </pre>
128 *
129 * <p>
130 *   As this component was introduced in version 6.0, the pattern described above can't be
131 *   exactly applied when plugin must support version 5.6 Long Term Support. In this case plugin
132 *   should use {@link SonarQubeVersion}, for example through {@link Plugin.Context#getSonarQubeVersion()} or
133 *   {@link SensorContext#getSonarQubeVersion()}.
134 * </p>
135 *
136 * <p>
137 * Unit tests of plugin extensions can create instances of {@link SonarRuntime}
138 * via {@link org.sonar.api.internal.SonarRuntimeImpl}.
139 * </p>
140 * @since 6.0
141 */
142@ScannerSide
143@ServerSide
144@ComputeEngineSide
145@SonarLintSide
146@Immutable
147public interface SonarRuntime {
148
149  /**
150   * Version of API (sonar-plugin-api artifact) at runtime.
151   * It can be helpful to call some API classes/methods without checking their availability at
152   * runtime by using reflection.
153   * <br/>
154   * Since 6.3, the returned version includes the build number in the fourth field, for
155   * example {@code "6.3.0.12345"}.
156  */
157  Version getApiVersion();
158
159  /**
160   * The product being executed at runtime. It targets analysers so that they can implement
161   * different behaviours in SonarQube and SonarLint.
162   */
163  SonarProduct getProduct();
164
165  /**
166   * The SonarQube stack being executed at runtime.
167   * @throws UnsupportedOperationException if {@link #getProduct()} is not equal to {@link SonarProduct#SONARQUBE}
168   */
169  SonarQubeSide getSonarQubeSide();
170
171}