]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2881 Do not rebuild the WAR file when changing conf/logback.xml
authorsimonbrandhof <simon.brandhof@gmail.com>
Sun, 9 Oct 2011 16:44:11 +0000 (18:44 +0200)
committersimonbrandhof <simon.brandhof@gmail.com>
Sun, 9 Oct 2011 16:44:11 +0000 (18:44 +0200)
31 files changed:
pom.xml
sonar-application/pom.xml
sonar-application/src/main/assembly/conf/logback.xml
sonar-application/src/main/assembly/war/build.xml
sonar-application/src/main/java/org/sonar/application/JettyEmbedder.java
sonar-application/src/main/java/org/sonar/application/StartServer.java
sonar-batch/src/main/java/org/sonar/batch/config/BatchSettingsEnhancer.java
sonar-batch/src/main/java/org/sonar/batch/config/ProjectSettings.java
sonar-channel/pom.xml
sonar-core/src/main/java/org/sonar/core/config/ConfigurationUtils.java
sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java
sonar-server/pom.xml
sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java [deleted file]
sonar-server/src/main/java/org/sonar/server/database/JndiDatabaseConnector.java
sonar-server/src/main/java/org/sonar/server/mavendeployer/MavenRepository.java
sonar-server/src/main/java/org/sonar/server/platform/DefaultServerFileSystem.java
sonar-server/src/main/java/org/sonar/server/platform/Logback.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/Platform.java
sonar-server/src/main/java/org/sonar/server/platform/PlatformLifecycleListener.java
sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/ServerStartException.java
sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/startup/GwtPublisher.java
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java
sonar-server/src/main/resources/sonar-war.properties
sonar-server/src/main/webapp/WEB-INF/web.xml
sonar-server/src/test/java/org/sonar/server/database/JndiDatabaseConnectorTest.java
sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties [new file with mode: 0644]
sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/db/shared.xml [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index a36d3e34bf9a34326ddc8df99b09abcfb145c0d0..24d15e4a77a7cb7b716cf82b9481dddcad0cbb87 100644 (file)
--- a/pom.xml
+++ b/pom.xml
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
-        <version>1.5.6</version>
+        <version>1.6.2</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jcl-over-slf4j</artifactId>
-        <version>1.5.6</version>
+        <version>1.6.2</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>log4j-over-slf4j</artifactId>
-        <version>1.5.6</version>
+        <version>1.6.2</version>
       </dependency>
       <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
-        <version>0.9.15</version>
+        <version>0.9.30</version>
       </dependency>
       <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-core</artifactId>
-        <version>0.9.15</version>
-      </dependency>
-      <dependency>
-        <groupId>janino</groupId>
-        <artifactId>janino</artifactId>
-        <version>2.5.10</version>
+        <version>0.9.30</version>
       </dependency>
       <dependency>
         <groupId>org.apache.derby</groupId>
index 2e009da50ef87368988a8c65276d5f56896c9c0e..f4c91172d7aa3276b6331863b3f17b0c68176f71 100644 (file)
       <artifactId>sonar-testing-harness</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>jcl-over-slf4j</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>ch.qos.logback</groupId>
-      <artifactId>logback-classic</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>ch.qos.logback</groupId>
-      <artifactId>logback-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>janino</groupId>
-      <artifactId>janino</artifactId>
-    </dependency>
     <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
index 407cbdbe265b5fe00c802ea4c00647350365d6ee..e84e65ad635868c7a0886798b216cb74e6936b18 100644 (file)
@@ -2,72 +2,42 @@
 
 <configuration debug="false">
 
-  <!-- appender used when deploying Sonar WAR on a JEE server -->
-  <appender name="SONAR_WAR" class="ch.qos.logback.core.ConsoleAppender">
-    <!-- avoid to log 404 file not found messages from the rails file servlet -->
-    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
-      <evaluator name="mavenRepoFileNotFound">
-        <expression>message.startsWith("files: File not found: /maven")</expression>
-      </evaluator>
-      <OnMismatch>NEUTRAL</OnMismatch>
-      <OnMatch>DENY</OnMatch>
-    </filter>
-    <layout class="ch.qos.logback.classic.PatternLayout">
-      <pattern>
-        %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n
-      </pattern>
-    </layout>
-  </appender>
-
-  <!-- SONAR_STANDALONE/ -->
-  <!-- do not edit/remove the previous comment -->
   <appender name="SONAR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-    <File>../../logs/sonar.log</File>
+    <File>${SONAR_HOME}/logs/sonar.log</File>
     <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
-      <param name="FileNamePattern" value="../../logs/sonar.%i.log"/>
+      <param name="FileNamePattern" value="${SONAR_HOME}/logs/sonar.%i.log"/>
       <param name="MinIndex" value="1"/>
       <param name="MaxIndex" value="3"/>
     </rollingPolicy>
     <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
       <param name="MaxFileSize" value="5MB"/>
     </triggeringPolicy>
-    <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
-      <evaluator name="mavenRepoFileNotFound">
-        <expression>message.startsWith("files: File not found: /maven")</expression>
-      </evaluator>
-      <OnMismatch>NEUTRAL</OnMismatch>
-      <OnMatch>DENY</OnMatch>
-    </filter>
-    <layout class="ch.qos.logback.classic.PatternLayout">
+    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
       <pattern>
         %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n
       </pattern>
-    </layout>
+    </encoder>
   </appender>
 
   <!-- appender used to profile Sonar Server -->
   <appender name="PROFILING_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-    <File>../../logs/profiling.log</File>
+    <File>${SONAR_HOME}/logs/profiling.log</File>
     <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
-      <param name="FileNamePattern" value="../../logs/profiling.%i.log"/>
+      <param name="FileNamePattern" value="${SONAR_HOME}/logs/profiling.%i.log"/>
       <param name="MinIndex" value="1"/>
       <param name="MaxIndex" value="3"/>
     </rollingPolicy>
     <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
       <param name="MaxFileSize" value="5MB"/>
     </triggeringPolicy>
-    <layout class="ch.qos.logback.classic.PatternLayout">
+    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
       <pattern>
         %d{yyyy.MM.dd HH:mm:ss} %-5level %logger{20} %X %msg%n
       </pattern>
-    </layout>
+    </encoder>
   </appender>
 
-  <!-- do not edit/remove the following comment -->
-  <!-- /SONAR_STANDALONE -->
-
-
-  <!-- 
+    <!--
     Profiling of JRuby on Rails requests . Uncomment in order to log HTTP and SQL requests.
     Execute the following command to get the HTTP requests with execution time > 10s :
     grep 'rails  Completed in [0-9]\{5,\}ms' < profiling.log
index 0832a7a58ff5a44e6a3d44d980888dcb5e8ea50b..9a2467fb881aecefed5823682282a2631ea64a9c 100644 (file)
@@ -32,25 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
       <fileset dir="../extensions/jdbc-driver" includes="**/*.jar"/>
     </copy>
 
-    <replace file="build/sonar-server/WEB-INF/classes/sonar-war.properties" token="#sonar.home=" value="sonar.home=${sonarHome}" />
-
-    <!-- copy the logback config -->
-    <copy todir="build/sonar-server/WEB-INF/classes">
-      <fileset dir="../conf" includes="logback.xml"/>
-    </copy>
-
-    <!-- remove appenders configured for standalone mode -->
-    <replace file="build/sonar-server/WEB-INF/classes/logback.xml">
-      <replacetoken><![CDATA[<appender-ref ref="SONAR_FILE"/>]]></replacetoken>
-      <replacevalue><![CDATA[<appender-ref ref="SONAR_WAR"/>]]></replacevalue>
-    </replace>
-    <replace file="build/sonar-server/WEB-INF/classes/logback.xml">
-      <replacetoken><![CDATA[<appender-ref ref="PROFILING_FILE"/>]]></replacetoken>
-      <replacevalue><![CDATA[<appender-ref ref="SONAR_WAR"/>]]></replacevalue>
-    </replace>
-
-    <!-- see SONAR-1811. The appender SONAR_FILE must be removed from logback configuration -->
-    <replaceregexp file="build/sonar-server/WEB-INF/classes/logback.xml" match="SONAR_STANDALONE/(.*)/SONAR_STANDALONE" replace="" byline="false" flags="gs"/>
+    <replace file="build/sonar-server/WEB-INF/classes/sonar-war.properties" token="#SONAR_HOME=" value="SONAR_HOME=${sonarHome}" />
 
     <war destfile="sonar.war" webxml="build/sonar-server/WEB-INF/web.xml">
       <fileset dir="build/sonar-server"/>
index 37b9c9c216b36cc53351e6d81fa6a70362ef9c4f..713ecab0267b57925de01021e0bc2db4740bb83c 100644 (file)
@@ -29,7 +29,6 @@ import org.mortbay.jetty.nio.SelectChannelConnector;
 import org.mortbay.jetty.webapp.WebAppContext;
 import org.mortbay.thread.QueuedThreadPool;
 import org.mortbay.xml.XmlConfiguration;
-import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
@@ -85,11 +84,12 @@ public class JettyEmbedder {
         try {
           server.stop();
         } catch (Exception e) {
-          LoggerFactory.getLogger(getClass()).error("Can not stop the Jetty server", e);
+          System.err.println("Can not stop the Jetty server");
+          e.printStackTrace();
         }
       }
     });
-    LoggerFactory.getLogger("org.sonar.INFO").info("Sonar started: " + toString());
+//    LoggerFactory.getLogger("org.sonar.INFO").info("Sonar started: " + toString());
   }
 
   private Server configureProgrammatically() throws URISyntaxException, IOException {
@@ -123,7 +123,7 @@ public class JettyEmbedder {
     connector.setAcceptors(2);
     connector.setConfidentialPort(8443);
     if (ajp13Port > 0) {
-      LoggerFactory.getLogger("org.sonar.INFO").info("AJP13 connector is on port " + ajp13Port);
+      System.out.println("AJP13 connector is on port " + ajp13Port);
       Connector ajpConnector = new Ajp13SocketConnector();
       ajpConnector.setPort(ajp13Port);
       server.addConnector(ajpConnector);
index c92b5069e6e49a870bc2567ce1becc30685e35f7..1af81c86d0ec3f82cac78d73c4d8cf4c188be18a 100644 (file)
@@ -34,7 +34,6 @@ public final class StartServer {
   }
 
   public static void main(String[] args) throws Exception {
-    configureLogback();
     configureHome();
 
     Properties configuration = getConfiguration();
@@ -51,7 +50,7 @@ public final class StartServer {
 
   private static void configureRequestLogs(JettyEmbedder jetty, Properties configuration) {
     String filenamePattern = configuration.getProperty("sonar.web.jettyRequestLogs");
-    if (filenamePattern!=null) {
+    if (filenamePattern != null) {
       jetty.configureRequestLogs(filenamePattern);
     }
   }
@@ -64,12 +63,7 @@ public final class StartServer {
 
   private static void configureHome() throws URISyntaxException {
     File confFile = new File(StartServer.class.getResource("/conf/sonar.properties").toURI());
-    System.setProperty("sonar.home", confFile.getParentFile().getParentFile().getAbsolutePath());
-  }
-
-  private static void configureLogback() throws URISyntaxException {
-    File confFile = new File(StartServer.class.getResource("/conf/logback.xml").toURI());
-    System.setProperty("logback.configurationFile", confFile.getAbsolutePath()); 
-    System.setProperty("logback.ContextSelector", "JNDI");
+    System.setProperty("SONAR_HOME" /* see constant org.sonar.server.platform.SonarHome.PROPERTY */,
+        confFile.getParentFile().getParentFile().getAbsolutePath());
   }
 }
index a770fa64adf3f99aa69ecc4e53e43778e85b9175..ec6030cf7474c9767dd221529bd87067b5e6bc5a 100644 (file)
@@ -44,7 +44,7 @@ public final class BatchSettingsEnhancer {
   public void start() {
     String projectKey = reactor.getRoot().getKey();
     setIfNotDefined(ConfigurationUtils.getProjectProperties(dbFactory, projectKey));
-    setIfNotDefined(ConfigurationUtils.getGlobalProperties(dbFactory));
+    setIfNotDefined(ConfigurationUtils.getGeneralProperties(dbFactory));
     settings.updateDeprecatedCommonsConfiguration();
   }
 
index 4fcc837791bbeb1042c5e34a30cfb35d44478b4b..ca5e52ff96d60bc4a72cf3c84c46f6487243d37d 100644 (file)
@@ -73,7 +73,7 @@ public class ProjectSettings extends Settings {
   }
 
   private void loadDatabaseGlobalSettings() {
-    List<Property> props = ConfigurationUtils.getGlobalProperties(dbFactory);
+    List<Property> props = ConfigurationUtils.getGeneralProperties(dbFactory);
     for (Property dbProperty : props) {
       setProperty(dbProperty.getKey(), dbProperty.getValue());
     }
index b6834b99a00d4ee19855b806f6a7bc81c577b652..1f5f17bdb6dd58a35a4603840c9c313fb8a8987b 100644 (file)
                        <artifactId>hamcrest-all</artifactId>
                        <scope>test</scope>
                </dependency>
-               <dependency>
-                       <groupId>ch.qos.logback</groupId>
-                       <artifactId>logback-classic</artifactId>
-                       <scope>test</scope>
-               </dependency>
        </dependencies>
 </project>
\ No newline at end of file
index bf4eda351a4f0f3e8c7a69587d4bfc26a4d098cc..e5ea9230a47a480d3b5122eaa1e822ab87206b59 100644 (file)
@@ -51,13 +51,13 @@ public final class ConfigurationUtils {
 
   public static Properties openProperties(File file) throws IOException {
     FileInputStream input = FileUtils.openInputStream(file);
-    return openInputStream(input);
+    return readInputStream(input);
   }
 
   /**
    * Note that the input stream is closed in this method.
    */
-  public static Properties openInputStream(InputStream input) throws IOException {
+  public static Properties readInputStream(InputStream input) throws IOException {
     try {
       Properties p = new Properties();
       p.load(input);
@@ -97,7 +97,7 @@ public final class ConfigurationUtils {
     return Collections.emptyList();
   }
 
-  public static List<Property> getGlobalProperties(DatabaseSessionFactory dbFactory) {
+  public static List<Property> getGeneralProperties(DatabaseSessionFactory dbFactory) {
     DatabaseSession session = prepareDbSession(dbFactory);
     return session
         .createQuery("from " + Property.class.getSimpleName() + " p where p.resourceId is null and p.userId is null")
index 958e01870d38f937dc4c6b8d6da5ad58bc8acf4a..d6eb8becffa49317974e7f1b0dab704417cb2557 100644 (file)
@@ -64,7 +64,7 @@ public interface CoreProperties {
 
 
   /* Global settings */
-  String SONAR_HOME = "sonar.home";
+  String SONAR_HOME = "SONAR_HOME";
   String PROJECT_BRANCH_PROPERTY = "sonar.branch";
   String PROJECT_VERSION_PROPERTY = "sonar.projectVersion";
 
index 33a79cde6649d6f8705741492c8594a3cfae816e..4cd62ce8577691aa4f3711e592b4c127097233c9 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.codehaus.sonar</groupId>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.picocontainer</groupId>
       <artifactId>picocontainer</artifactId>
       <groupId>jfree</groupId>
       <artifactId>jfreechart</artifactId>
     </dependency>
+
+    <!-- logging -->
     <dependency>
-      <groupId>janino</groupId>
-      <artifactId>janino</artifactId>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
     </dependency>
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>log4j-over-slf4j</artifactId>
+    </dependency>
+
+
     <dependency>
       <groupId>commons-dbcp</groupId>
       <artifactId>commons-dbcp</artifactId>
               </connectors>
               <systemProperties>
                 <systemProperty>
-                  <name>sonar.home</name>
+                  <name>SONAR_HOME</name>
                   <value>${project.build.directory}/sonar-dev-home</value>
                 </systemProperty>
               </systemProperties>
diff --git a/sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java b/sonar-server/src/main/java/org/sonar/server/configuration/ServerSettings.java
deleted file mode 100644 (file)
index 72b0afb..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2011 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * Sonar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
- */
-package org.sonar.server.configuration;
-
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-import org.sonar.api.database.DatabaseSession;
-import org.sonar.api.database.configuration.Property;
-import org.sonar.core.config.ConfigurationUtils;
-import org.sonar.jpa.session.DatabaseSessionFactory;
-
-import javax.servlet.ServletContext;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Properties;
-
-/**
- * Load settings from environment, conf/sonar.properties and database
- *
- * @since 2.12
- */
-public class ServerSettings extends Settings {
-
-  public static final String DEPLOY_DIR = "sonar.web.deployDir";
-
-  private DatabaseSessionFactory sessionFactory;
-  private Configuration deprecatedConfiguration;
-  private File sonarHome;
-  private File deployDir;
-
-  public ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, ServletContext servletContext) {
-    super(definitions);
-    this.deprecatedConfiguration = deprecatedConfiguration;
-    this.sonarHome = getSonarHome();
-    this.deployDir = getDeployDir(servletContext);
-    load();
-  }
-
-  public ServerSettings setSessionFactory(DatabaseSessionFactory sessionFactory) {
-    this.sessionFactory = sessionFactory;
-    return this;
-  }
-
-  public ServerSettings load() {
-    clear();
-    setProperty(CoreProperties.SONAR_HOME, sonarHome.getAbsolutePath());
-    setProperty(DEPLOY_DIR, deployDir.getAbsolutePath());
-
-    // order is important
-    loadDatabaseSettings();
-    addEnvironmentVariables();
-    addSystemProperties();
-    loadPropertiesFile();
-
-    // update deprecated configuration
-    ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedConfiguration);
-
-    return this;
-  }
-
-  private void loadDatabaseSettings() {
-    if (sessionFactory != null) {
-      DatabaseSession session = sessionFactory.getSession();
-
-      // Ugly workaround before the move to myBatis
-      // Session is not up-to-date when Ruby on Rails inserts new rows in its own transaction. Seems like
-      // Hibernate keeps a cache...
-      session.commit();
-      List<Property> properties = session.createQuery("from " + Property.class.getSimpleName() + " p where p.resourceId is null and p.userId is null").getResultList();
-
-      for (Property property : properties) {
-        setProperty(property.getKey(), property.getValue());
-      }
-    }
-  }
-
-  private void loadPropertiesFile() {
-    File propertiesFile = new File(sonarHome, "conf/sonar.properties");
-    if (!propertiesFile.isFile() || !propertiesFile.exists()) {
-      throw new IllegalStateException("Properties file does not exist: " + propertiesFile);
-    }
-
-    try {
-      Properties p = ConfigurationUtils.openProperties(propertiesFile);
-      p = ConfigurationUtils.interpolateEnvVariables(p);
-      addProperties(p);
-
-    } catch (Exception e) {
-      throw new IllegalStateException("Fail to load configuration file: " + propertiesFile, e);
-    }
-  }
-
-  static File getDeployDir(ServletContext servletContext) {
-    String dirname = servletContext.getRealPath("/deploy/");
-    if (dirname == null) {
-      throw new IllegalArgumentException("Web app directory not found : /deploy/");
-    }
-    File dir = new File(dirname);
-    if (!dir.exists()) {
-      throw new IllegalArgumentException("Web app directory does not exist: " + dir);
-    }
-    return dir;
-  }
-
-  static File getSonarHome() {
-    String home = System.getProperty("sonar.home");
-    if (StringUtils.isBlank(home)) {
-      home = System.getenv("SONAR_HOME");
-      if (StringUtils.isBlank(home)) {
-        Properties warProps = openWarProperties();
-        home = warProps.getProperty("sonar.home");
-      }
-    }
-
-    if (StringUtils.isBlank(home)) {
-      throw new IllegalStateException("Please set location to SONAR_HOME");
-    }
-
-    File dir = new File(home);
-    if (!dir.isDirectory() || !dir.exists()) {
-      throw new IllegalStateException("SONAR_HOME is not valid: " + home);
-    }
-    return dir;
-  }
-
-  private static Properties openWarProperties() {
-    try {
-      InputStream input = ServerSettings.class.getResourceAsStream("/sonar-war.properties");
-      return ConfigurationUtils.openInputStream(input);
-    } catch (IOException e) {
-      throw new IllegalStateException("Fail to load the file sonar-war.properties", e);
-    }
-  }
-}
index 52d016c0b0eb7192e1e221eee73b3c229b436be0..d4742cda149557bb0f7d8bb1b1e526b6f00485b1 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.database;
 
-import org.apache.commons.configuration.Configuration;
 import org.apache.commons.dbcp.BasicDataSourceFactory;
 import org.apache.commons.lang.StringUtils;
 import org.hibernate.cfg.Environment;
@@ -32,7 +31,6 @@ import org.sonar.jpa.session.AbstractDatabaseConnector;
 import javax.sql.DataSource;
 import java.sql.Connection;
 import java.sql.SQLException;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Properties;
 
index bf956a5949e49a951e58f33ef0261473b8a5b8c6..3fc026d06292ce9affb124da984ca8556999164f 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.mavendeployer;
 import org.apache.commons.io.FileUtils;
 import org.sonar.api.config.Settings;
 import org.sonar.api.platform.Server;
-import org.sonar.server.configuration.ServerSettings;
+import org.sonar.server.platform.ServerSettings;
 import org.sonar.server.platform.DefaultServerFileSystem;
 
 import java.io.File;
index a3ea2935404215757c47e6cab04f731dd2207c1e..ab70ba9018872c93723189137fd3fa418960dc4e 100644 (file)
@@ -26,7 +26,6 @@ import org.sonar.api.config.Settings;
 import org.sonar.api.platform.ServerFileSystem;
 import org.sonar.api.utils.Logs;
 import org.sonar.jpa.session.DatabaseConnector;
-import org.sonar.server.configuration.ServerSettings;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Logback.java b/sonar-server/src/main/java/org/sonar/server/platform/Logback.java
new file mode 100644 (file)
index 0000000..eec641e
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.platform;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.util.StatusPrinter;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ * Configure Logback with $SONAR_HOME/conf/logback.xml
+ *
+ * @since 2.12
+ */
+final class Logback {
+
+  static void configure() {
+    configure(new File(SonarHome.getHome(), "conf/logback.xml"));
+  }
+
+  static void configure(File logbackFile) {
+    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+    try {
+      JoranConfigurator configurator = new JoranConfigurator();
+      configurator.setContext(lc);
+      lc.reset();
+      configurator.doConfigure(logbackFile);
+    } catch (JoranException e) {
+      // StatusPrinter will handle this
+    }
+    StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
+  }
+}
index 8f65905de3e1d04cbe4a97927ba7523624dfe92f..3c4ae6601ce6fb1ac6195a6345563a0f0a9a6aad 100644 (file)
@@ -50,7 +50,6 @@ import org.sonar.jpa.session.DatabaseSessionFactory;
 import org.sonar.jpa.session.DatabaseSessionProvider;
 import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
 import org.sonar.server.charts.ChartFactory;
-import org.sonar.server.configuration.ServerSettings;
 import org.sonar.server.configuration.Backup;
 import org.sonar.server.configuration.ProfilesManager;
 import org.sonar.server.database.EmbeddedDatabaseFactory;
index 526e4f6823964becc8dcb5733c513478280c189c..10dcb45375cb0c3ce2e473e3a3bd2ffcdedb7991 100644 (file)
@@ -25,6 +25,7 @@ import javax.servlet.ServletContextListener;
 public final class PlatformLifecycleListener implements ServletContextListener {
 
   public void contextInitialized(ServletContextEvent event) {
+    Logback.configure();
     Platform.getInstance().init(event.getServletContext());
     Platform.getInstance().start();
   }
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerSettings.java
new file mode 100644 (file)
index 0000000..2dc7409
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.platform;
+
+import org.apache.commons.configuration.Configuration;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.api.database.configuration.Property;
+import org.sonar.core.config.ConfigurationUtils;
+import org.sonar.jpa.session.DatabaseSessionFactory;
+
+import javax.servlet.ServletContext;
+import java.io.File;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * Load settings in the following order (the last override the first) :
+ * <ol>
+ * <li>general settings persisted in database</li>
+ * <li>file $SONAR_HOME/conf/sonar.properties</li>
+ * <li>environment variables</li>
+ * <li>system properties</li>
+ * </ol>
+ *
+ * @since 2.12
+ */
+public class ServerSettings extends Settings {
+
+  public static final String DEPLOY_DIR = "sonar.web.deployDir";
+
+  private DatabaseSessionFactory sessionFactory;
+  private Configuration deprecatedConfiguration;
+  private File deployDir;
+
+  public ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, ServletContext servletContext) {
+    super(definitions);
+    this.deprecatedConfiguration = deprecatedConfiguration;
+    this.deployDir = getDeployDir(servletContext);
+    load();
+  }
+
+  ServerSettings(PropertyDefinitions definitions, Configuration deprecatedConfiguration, File deployDir, File sonarHome) {
+    super(definitions);
+    this.deprecatedConfiguration = deprecatedConfiguration;
+    this.deployDir = deployDir;
+    load(sonarHome);
+  }
+
+  public ServerSettings setSessionFactory(DatabaseSessionFactory sessionFactory) {
+    this.sessionFactory = sessionFactory;
+    return this;
+  }
+
+  public ServerSettings load() {
+    return load(SonarHome.getHome());
+  }
+
+  ServerSettings load(File sonarHome) {
+    clear();
+    setProperty(CoreProperties.SONAR_HOME, sonarHome.getAbsolutePath());
+    setProperty(DEPLOY_DIR, deployDir.getAbsolutePath());
+    
+    // order is important : the last override the first
+    loadDatabaseSettings();
+    loadPropertiesFile(sonarHome);
+    addEnvironmentVariables();
+    addSystemProperties();
+
+    // update deprecated configuration
+    ConfigurationUtils.copyToCommonsConfiguration(properties, deprecatedConfiguration);
+
+    return this;
+  }
+
+  private void loadDatabaseSettings() {
+    if (sessionFactory != null) {
+      List<Property> properties = ConfigurationUtils.getGeneralProperties(sessionFactory);
+      for (Property property : properties) {
+        setProperty(property.getKey(), property.getValue());
+      }
+    }
+  }
+
+  private void loadPropertiesFile(File sonarHome) {
+    File propertiesFile = new File(sonarHome, "conf/sonar.properties");
+    if (!propertiesFile.isFile() || !propertiesFile.exists()) {
+      throw new IllegalStateException("Properties file does not exist: " + propertiesFile);
+    }
+
+    try {
+      Properties p = ConfigurationUtils.openProperties(propertiesFile);
+      p = ConfigurationUtils.interpolateEnvVariables(p);
+      addProperties(p);
+    } catch (Exception e) {
+      throw new IllegalStateException("Fail to load configuration file: " + propertiesFile, e);
+    }
+  }
+
+  static File getDeployDir(ServletContext servletContext) {
+    String dirname = servletContext.getRealPath("/deploy/");
+    if (dirname == null) {
+      throw new IllegalArgumentException("Web app directory not found : /deploy/");
+    }
+    File dir = new File(dirname);
+    if (!dir.exists()) {
+      throw new IllegalArgumentException("Web app directory does not exist: " + dir);
+    }
+    return dir;
+  }
+}
index 828c80505e22032370f3ff46b75fc726a493ec6d..e1cd5522226807e3be48b47ba07a21477c1d131c 100644 (file)
@@ -21,9 +21,6 @@ package org.sonar.server.platform;
 
 public class ServerStartException extends RuntimeException {
 
-  public ServerStartException() {
-  }
-
   public ServerStartException(String s) {
     super(s);
   }
@@ -31,8 +28,4 @@ public class ServerStartException extends RuntimeException {
   public ServerStartException(String s, Throwable throwable) {
     super(s, throwable);
   }
-
-  public ServerStartException(Throwable throwable) {
-    super(throwable);
-  }
 }
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java b/sonar-server/src/main/java/org/sonar/server/platform/SonarHome.java
new file mode 100644 (file)
index 0000000..454f2fd
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.platform;
+
+import org.apache.commons.lang.StringUtils;
+import org.sonar.core.config.ConfigurationUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * Search fo the Sonar installation directory in the following ordered steps :
+ * <ol>
+ *   <li>system property SONAR_HOME</li>
+ *   <li>environment variable SONAR_HOME</li>
+ *   <li>property SONAR_HOME in the file WEB-INF/classes/sonar-war.properties</li>
+ * </ol>
+ * 
+ * @since 2.12
+ */
+final class SonarHome {
+
+  static final String PROPERTY = "SONAR_HOME";
+  private static File home;
+
+  static File getHome() {
+    if (home == null) {
+      home = locate();
+      System.setProperty(PROPERTY, home.getAbsolutePath());
+    }
+    return home;
+  }
+
+  static File locate() {
+    String home = System.getProperty(PROPERTY);
+    if (StringUtils.isBlank(home)) {
+      home = System.getenv(PROPERTY);
+      if (StringUtils.isBlank(home)) {
+        home = openWarProperties().getProperty(PROPERTY);
+      }
+    }
+
+    if (StringUtils.isBlank(home)) {
+      throw new IllegalStateException("Sonar home is not defined. " +
+          "Please set the environment variable/system property " + PROPERTY + " or edit the file WEB-INF/classes/sonar-war.properties");
+    }
+
+    File dir = new File(home);
+    if (!dir.isDirectory() || !dir.exists()) {
+      throw new IllegalStateException(PROPERTY + " is not valid: " + home + ". Please fix the environment variable/system property SONAR_HOME or " +
+          "the file WEB-INF/classes/sonar-war.properties");
+    }
+    return dir;
+  }
+
+  private static Properties openWarProperties() {
+    try {
+      InputStream input = SonarHome.class.getResourceAsStream("/sonar-war.properties");
+      return ConfigurationUtils.readInputStream(input); // it closes the stream
+    } catch (IOException e) {
+      throw new IllegalStateException("Fail to load the file sonar-war.properties", e);
+    }
+  }
+}
index f61f2bc1b735c5617d4d74a3ab2ac6fd2e8a2f4c..6f3e0c69e5266fc9473ae0c65ddb029ac494c8d4 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.api.utils.SonarException;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.api.utils.ZipUtils;
 import org.sonar.api.web.GwtExtension;
-import org.sonar.server.configuration.ServerSettings;
+import org.sonar.server.platform.ServerSettings;
 
 import java.io.File;
 import java.io.IOException;
index 59598488060843e0951b73a273ca04ed373a268c..e4747e37a89dd04bbf19f119f56d911858a6d2db 100644 (file)
@@ -37,7 +37,7 @@ import org.sonar.core.i18n.RuleI18nManager;
 import org.sonar.jpa.dialect.Dialect;
 import org.sonar.jpa.session.DatabaseConnector;
 import org.sonar.markdown.Markdown;
-import org.sonar.server.configuration.ServerSettings;
+import org.sonar.server.platform.ServerSettings;
 import org.sonar.server.configuration.Backup;
 import org.sonar.server.configuration.ProfilesManager;
 import org.sonar.server.filters.Filter;
index f0787339955914d44a5b52e35e6512e88d0c2608..de2350c3887b33722c7920332b2df94dbe5290e8 100644 (file)
@@ -1,9 +1,5 @@
 # This file is used only when deploying the webapp to an application server.
 # It is ignored when using the standalone mode shipped by default.
 
-# The path to the Sonar home directory must be defined :
-# - by setting the environment variable SONAR_HOME in the app server
-# - or by setting the system property sonar.home in the app server
-# - or by uncommenting and setting the following property before deploying the webapp
-
-#sonar.home=
\ No newline at end of file
+# Path to Sonar installation directory, if the environment variable/system property SONAR_HOME is not defined
+#SONAR_HOME=
\ No newline at end of file
index cdc3a9d3ca8fad25238cd17bf005bed6d2761857..23172c43dbe48fe6ddfc826a798652cad82e2a05 100644 (file)
     <param-value>1</param-value>
   </context-param>
 
-  <env-entry>
-    <description>JNDI logback context</description>
-    <env-entry-name>logback/context-name</env-entry-name>
-    <env-entry-type>java.lang.String</env-entry-type>
-    <env-entry-value>Sonar</env-entry-value>
-  </env-entry>
-
   <filter>
     <filter-name>DatabaseSessionFilter</filter-name>
     <filter-class>org.sonar.server.ui.DatabaseSessionFilter</filter-class>
   <listener>
     <listener-class>org.jruby.rack.rails.RailsServletContextListener</listener-class>
   </listener>
-  <listener>
-    <listener-class>ch.qos.logback.classic.selector.servlet.ContextDetachingSCL</listener-class>
-  </listener>
 
 </web-app>
index aa2e30497a7a761b8ff3a1d6718f7242f0bd6434..898c460569755f0e6f2a7543eb71d817f9033f72 100644 (file)
  */
 package org.sonar.server.database;
 
-import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.config.Settings;
 import org.sonar.api.database.DatabaseProperties;
 import org.sonar.jpa.entity.SchemaMigration;
-import org.sonar.server.configuration.ServerSettings;
 
 import javax.naming.Context;
 import javax.persistence.EntityManagerFactory;
diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerSettingsTest.java
new file mode 100644 (file)
index 0000000..148853d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.platform;
+
+import org.apache.commons.configuration.BaseConfiguration;
+import org.junit.Test;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.jpa.test.AbstractDbUnitTestCase;
+
+import java.io.File;
+import java.net.URISyntaxException;
+
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+public class ServerSettingsTest extends AbstractDbUnitTestCase {
+
+  private static File home = getHome();
+
+  @Test
+  public void shouldLoadPropertiesFile() throws URISyntaxException {
+    ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home);
+
+    assertThat(settings.getString("hello"), is("world"));
+  }
+
+  @Test
+  public void systemPropertiesShouldOverridePropertiesFile() throws URISyntaxException {
+    System.setProperty("ServerSettingsTestEnv", "in_env");
+    ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home);
+
+    assertThat(settings.getString("ServerSettingsTestEnv"), is("in_env"));
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void shouldFailIfPropertiesFileNotFound() {
+    File sonarHome = new File("unknown/path");
+    new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), sonarHome);
+  }
+
+  @Test
+  public void shouldLoadPersistedGeneralSettings() throws URISyntaxException {
+    setupData("db/shared");
+
+    ServerSettings settings = new ServerSettings(new PropertyDefinitions(), new BaseConfiguration(), new File("."), home);
+    settings.setSessionFactory(getSessionFactory());
+    settings.load(home);
+
+    assertThat(settings.getString("general_only"), is("is_general"));
+    assertThat(settings.getString("general_and_project"), is("is_general"));
+    assertThat(settings.getString("project_only"), nullValue());
+  }
+
+  private static File getHome() {
+    try {
+      return new File(ServerSettingsTest.class.getResource("/org/sonar/server/platform/ServerSettingsTest/").toURI());
+    } catch (URISyntaxException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java b/sonar-server/src/test/java/org/sonar/server/platform/SonarHomeTest.java
new file mode 100644 (file)
index 0000000..69a652e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
+ */
+package org.sonar.server.platform;
+
+import org.junit.Test;
+
+public class SonarHomeTest {
+  @Test
+  public void iDontKnowHowToSimplyTestThisClass() {
+
+  }
+}
diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties b/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/conf/sonar.properties
new file mode 100644 (file)
index 0000000..016382d
--- /dev/null
@@ -0,0 +1,2 @@
+hello: world
+ServerSettingsTestEnv: in_file
\ No newline at end of file
diff --git a/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/db/shared.xml b/sonar-server/src/test/resources/org/sonar/server/platform/ServerSettingsTest/db/shared.xml
new file mode 100644 (file)
index 0000000..f3a1b30
--- /dev/null
@@ -0,0 +1,20 @@
+<dataset>
+
+  <!-- project -->
+  <projects long_name="[null]" id="3333" scope="PRJ" qualifier="TRK" kee="mygroup:anotherproject" name="[null]"
+            root_id="[null]"
+            description="[null]"
+            enabled="true" language="java" copy_resource_id="[null]"/>
+
+  <!-- general properties -->
+  <properties prop_key="general_only" resource_id="[null]" user_id="[null]" text_value="is_general"/>
+  <properties prop_key="general_and_project" resource_id="[null]" user_id="[null]" text_value="is_general"/>
+
+  <!-- project properties: do not load  -->
+  <properties prop_key="general_and_project" resource_id="3333" user_id="[null]" text_value="is_project"/>
+  <properties prop_key="project_only" resource_id="3333" user_id="[null]" text_value="is_project"/>
+
+  <!-- user properties : do not load -->
+  <properties prop_key="user" resource_id="[null]" user_id="110" text_value="is_user"/>
+
+</dataset>
\ No newline at end of file