開発中とリリース後で処理を切り替える

Gradle 前提だけど、他のビルドツールでもできるはず。

#スタンドアロンアプリ
##フォルダ構成
```text
app/
|-build.gradle
`-src/main/
   |-java/
   |  `-Main.java
   `-resources/
     `-log4j.xml
```

##実装
```xml:log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >

  <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
     <param name="Target" value="System.out" /> 
     <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%m%n" />
     </layout>
  </appender>

  <root>
    <level value ="${log.level}" />
    <appender-ref ref="stdout"/>
  </root>
</log4j:configuration>
```

```java:Main.java
import org.apache.log4j.Logger;

public class Main {
    public static void main(String[] args) {
        boolean isRelease = Boolean.valueOf(System.getProperty("isRelease"));
        
        if (isRelease) {
            System.out.println("Release Mode");
            System.setProperty("log.level", "INFO");
        } else {
            System.out.println("Develop Mode");
            System.setProperty("log.level", "TRACE");
        }
        
        Logger logger = Logger.getLogger(Main.class);
        
        logger.trace("trace message");
        logger.debug("debug message");
        logger.info("info message");
    }
}
```

```groovy:build.gradle
apply plugin: 'application'

mainClassName = 'Main'

repositories {
    mavenCentral()
}

dependencies {
    compile 'log4j:log4j:1.2.17'
}

startScripts {
    defaultJvmOpts += ['-DisRelease=true']
}
```

##動作確認
###開発中の状態で実行
```text
> gradle -q run
Develop Mode
trace message
debug message
info message
```

###ビルドしてから実行
```text:ビルド
> gradle distZip
```

build/distributions/app.zip を解凍。
bin の下の起動ファイルを実行する。

```text:実行
> build\distributions\app\bin\app.bat
Release Mode
info message
```

##説明
システムプロパティ `isRelease` に `true` が設定されているかどうかで処理を分岐している。
`isRelease` の値は、 Gradle の Application プラグインにある `startScripts.defaultJvmOpts` で設定することで、リリース後のみ `true` が適用されるようにしている。

Log4j は `${xxxx}` という形式でシステムプロパティの値を参照できる。
これを利用して、 Log4j のロガーを最初に取得する前に、システムプロパティに必要な値を設定している。

#ウェブアプリ
##フォルダ構成
```text:
webapp/
|-build.gradle
`-src/main/
   |-java/
   |  |-MyListener.java
   |  `-MyServlet.java
   |-resources/
   |  `-log4j.xml
   `-webapp/WEB-INF
      `-web.xml
```

##実装
- log4j.xml の実装はスタンドアロンのときと同じ。

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  
  <listener>
    <listener-class>MyListener</listener-class>
  </listener>
  
  <servlet>
    <servlet-name>MyServlet</servlet-name>
    <servlet-class>MyServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>MyServlet</servlet-name>
    <url-pattern>/my-servlet</url-pattern>
  </servlet-mapping>
  
</web-app>
```

```java:MyListener.java
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;

public class MyListener implements ServletContextListener {
    
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        if (this.isRelease()) {
            System.out.println("Release Mode");
            System.setProperty("log.level", "INFO");
        } else {
            System.out.println("Develop Mode");
            System.setProperty("log.level", "TRACE");
        }
    }
    
    private boolean isRelease() {
        return MyListener.class.getResource("/is_release") != null;
    }
    
    @Override public void contextDestroyed(ServletContextEvent sce) {/*no use*/}
}
```

```java:MyServlet.java
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

public class MyServlet extends HttpServlet {
    
    private static final Logger logger = Logger.getLogger(MyServlet.class);
    
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        logger.trace("trace message");
        logger.debug("debug message");
        logger.info("info message");
    }
}
```

```groovy:build.gradle
apply plugin: 'jetty'

repositories {
    mavenCentral()
}

dependencies {
    compile 'log4j:log4j:1.2.17'
    providedCompile 'javax.servlet:servlet-api:2.5'
}

war {
    doFirst {
        def releaseFlagFile = new File(buildDir, 'tmp/release/is_release')
        
        releaseFlagFile.with {
            parentFile.mkdirs()
            createNewFile()
        }
        
        classpath += files(releaseFlagFile.parent)
    }
}
```

##動作確認
###開発中の状態で実行
```text:
> gradle jettyRun
:compileJava
:processResources
:classes
:jettyRun
Develop Mode
> Building 75% > :jettyRun > Running at http://localhost:8080/webapp
```

ブラウザを開いて `http://localhost:8080/webapp/my-servlet` にアクセスする。

```text:コンソール出力
trace message
debug message
info message
```

###生成したwarファイルで実行
```text:
> gradle jettyRunWar
:compileJava
:processResources
:classes
:war
:jettyRunWar
Release Mode
> Building 80% > :jettyRunWar > Running at http://localhost:8080/webapp
```

ブラウザを開いて `http://localhost:8080/webapp/my-servlet` にアクセスする。

```text:コンソール出力
info message
```

##説明
`gradle war` したときだけ、クラスパス直下に `is_release` というファイルを配置。
Web アプリ起動時に `MyListener` が `is_release` の存在をチェックしている。



#参考
- [War - Gradle DSL Version 2.2-20140924021627+0000](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.tasks.bundling.War.html)
- [CreateStartScripts - Gradle DSL Version 2.2-20140924021627+0000](http://gradle.monochromeroad.com/docs/dsl/org.gradle.api.tasks.application.CreateStartScripts.html)
- [Project (Gradle API 2.1)](http://www.gradle.org/docs/current/javadoc/org/gradle/api/Project.html)