]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5237 - Moved Dao Back to server and Using ThreadPool for QueueWorker
authorStephane Gamard <stephane.gamard@searchbox.com>
Wed, 30 Apr 2014 05:45:12 +0000 (07:45 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Wed, 30 Apr 2014 08:31:17 +0000 (10:31 +0200)
25 files changed:
sonar-core/src/main/java/org/sonar/core/cluster/ClusterAction.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/cluster/IndexAction.java [deleted file]
sonar-core/src/main/java/org/sonar/core/cluster/NullQueue.java
sonar-core/src/main/java/org/sonar/core/cluster/WorkQueue.java
sonar-core/src/main/java/org/sonar/core/db/BaseDao.java [deleted file]
sonar-core/src/main/java/org/sonar/core/persistence/DbSession.java
sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java
sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java
sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java
sonar-server/src/main/java/org/sonar/server/cluster/LocalQueueWorker.java
sonar-server/src/main/java/org/sonar/server/db/BaseDao.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleDao.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java
sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
sonar-server/src/main/java/org/sonar/server/search/Index.java
sonar-server/src/main/java/org/sonar/server/search/IndexAction.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java
sonar-server/src/main/java/org/sonar/server/search/IndexUtils.java
sonar-server/src/test/java/org/sonar/server/cluster/LocalNonBlockingWorkQueueTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/cluster/LocalQueueWorkerTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/rule2/RuleDaoTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/rule2/RuleMediumTest.java

diff --git a/sonar-core/src/main/java/org/sonar/core/cluster/ClusterAction.java b/sonar-core/src/main/java/org/sonar/core/cluster/ClusterAction.java
new file mode 100644 (file)
index 0000000..c405263
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.core.cluster;
+
+import java.util.concurrent.CountDownLatch;
+
+public abstract class ClusterAction implements Runnable {
+
+  private CountDownLatch latch;
+
+  public ClusterAction(CountDownLatch latch){
+    this.latch = latch;
+  }
+
+  public ClusterAction() {
+    this.latch = null;
+  }
+
+  public void setLatch(CountDownLatch latch){
+    this.latch = latch;
+  }
+
+  public abstract void doExecute();
+
+  @Override
+  public void run(){
+    this.doExecute();
+    if(latch != null){
+      latch.countDown();
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/cluster/IndexAction.java b/sonar-core/src/main/java/org/sonar/core/cluster/IndexAction.java
deleted file mode 100644 (file)
index 7ed3c0d..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.core.cluster;
-
-import java.io.Serializable;
-
-public class IndexAction<K extends Serializable> {
-
-  public enum Method {
-    INSERT, UPDATE, DELETE
-  }
-
-  String indexName;
-  K key;
-  Method method;
-
-  public IndexAction(String indexName, Method method, K key){
-    this.indexName = indexName;
-    this.method = method;
-    this.key = key;
-  }
-
-  public String getIndexName() {
-    return indexName;
-  }
-
-  public void setIndexName(String indexName) {
-    this.indexName = indexName;
-  }
-
-  public K getKey() {
-    return key;
-  }
-
-  public void setKey(K key) {
-    this.key = key;
-  }
-
-  public Method getMethod() {
-    return method;
-  }
-
-  public void setMethod(Method method) {
-    this.method = method;
-  }
-}
index d18ed3e690c8e55ae3ec584395fbd11200bf0d5a..54df2784faa569ed9b67ddf8519250e98e61d834 100644 (file)
  */
 package org.sonar.core.cluster;
 
-import javax.annotation.CheckForNull;
+
 
 public class NullQueue implements WorkQueue {
 
   @Override
-  public void enqueue(IndexAction<?> action) {
+  public void enqueue(ClusterAction action) {
 
   }
 
   @Override
-  public void enqueue(Iterable<IndexAction<?>> actions) {
-
-  }
+  public void enqueue(Iterable<ClusterAction> actions) {
 
-  @CheckForNull
-  @Override
-  public IndexAction<?> dequeue() {
-    return null;
   }
 }
index 9c5ffcfbe026e72a4279655563bcfcb7b879eb48..cee9c63265e1d214dcd139bc964e0f97cfa5e25b 100644 (file)
  */
 package org.sonar.core.cluster;
 
-import javax.annotation.CheckForNull;
+import org.sonar.core.db.Dto;
+
+import java.io.Serializable;
+
+
 
 public interface WorkQueue {
 
-  void enqueue(IndexAction<?> action);
+  void enqueue(ClusterAction action);
 
-  void enqueue(Iterable<IndexAction<?>> actions);
+  void enqueue(Iterable<ClusterAction> actions);
 
-  @CheckForNull
-  IndexAction<?> dequeue();
+  /* This is because of core vs server packages... */
+//  void enqueue(ClusterAction.Type type, ClusterAction.Method method, String ref, Serializable key);
+//  void enqueue(ClusterAction.Type type, ClusterAction.Method method, String ref, Dto dto);
 
 }
diff --git a/sonar-core/src/main/java/org/sonar/core/db/BaseDao.java b/sonar-core/src/main/java/org/sonar/core/db/BaseDao.java
deleted file mode 100644 (file)
index bdc6143..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.core.db;
-
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.core.cluster.IndexAction;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-
-import java.io.Serializable;
-
-public abstract class BaseDao<E extends Dto<K>, K extends Serializable>
-  implements Dao<E, K> {
-
-  protected MyBatis mybatis;
-
-  protected BaseDao(MyBatis myBatis) {
-    this.mybatis = myBatis;
-  }
-
-  protected abstract String getIndexName();
-
-  protected abstract E doGetByKey(K key, SqlSession session);
-
-  protected abstract E doInsert(E item, SqlSession session);
-
-  protected abstract E doUpdate(E item, SqlSession session);
-
-  protected abstract void doDelete(E item, SqlSession session);
-
-  protected abstract void doDeleteByKey(K key, SqlSession session);
-
-  protected MyBatis getMyBatis() {
-    return this.mybatis;
-  }
-
-  @Override
-  public E getByKey(K key) {
-    DbSession session = getMyBatis().openSession(false);
-    E item = this.doGetByKey(key, session);
-    MyBatis.closeQuietly(session);
-    return item;
-  }
-
-  @Override
-  public E update(E item, DbSession session) {
-    session.enqueue(new IndexAction(this.getIndexName(),
-      IndexAction.Method.UPDATE, item.getKey()));
-    return this.doUpdate(item, session);
-  }
-
-  @Override
-  public E update(E item) {
-    DbSession session = getMyBatis().openSession(false);
-    try {
-      this.update(item, session);
-      session.commit();
-      return item;
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @Override
-  public E insert(E item, DbSession session) {
-    session.enqueue(new IndexAction(this.getIndexName(),
-      IndexAction.Method.INSERT, item.getKey()));
-    return this.doInsert(item, session);
-  }
-
-  @Override
-  public E insert(E item) {
-    DbSession session = getMyBatis().openSession(false);
-    try {
-      this.insert(item, session);
-      session.commit();
-      return item;
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @Override
-  public void delete(E item, DbSession session) {
-    session.enqueue(new IndexAction(this.getIndexName(),
-      IndexAction.Method.DELETE, item.getKey()));
-    this.doDelete(item, session);
-  }
-
-  @Override
-  public void delete(E item) {
-    DbSession session = getMyBatis().openSession(false);
-    try {
-      this.delete(item, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @Override
-  public void deleteByKey(K key, DbSession session) {
-    session.enqueue(new IndexAction(this.getIndexName(),
-      IndexAction.Method.DELETE, key));
-    this.doDeleteByKey(key, session);
-  }
-
-  @Override
-  public void deleteByKey(K key) {
-    DbSession session = getMyBatis().openSession(false);
-    try {
-      this.doDeleteByKey(key, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-}
index ea729a2f6660073f84ed7454451334d991df8d26..7653f69469660b0bfb379ad060be69c70bbf7167 100644 (file)
  */
 package org.sonar.core.persistence;
 
-import org.apache.ibatis.session.SqlSession;
-
 import org.apache.ibatis.executor.BatchResult;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.RowBounds;
-import org.sonar.core.cluster.IndexAction;
+import org.apache.ibatis.session.SqlSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.core.cluster.ClusterAction;
 import org.sonar.core.cluster.WorkQueue;
 
 import java.sql.Connection;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
 
 public class DbSession implements SqlSession {
 
-  private List<IndexAction<?>> actions;
+  private static final Logger LOG = LoggerFactory.getLogger(DbSession.class);
+
+  private List<ClusterAction> actions;
 
   private WorkQueue queue;
   private SqlSession session;
@@ -43,23 +47,36 @@ public class DbSession implements SqlSession {
   DbSession(WorkQueue queue, SqlSession session) {
     this.session = session;
     this.queue = queue;
-    this.actions = new ArrayList<IndexAction<?>>();
+    this.actions = new ArrayList<ClusterAction>();
   }
 
-  public void enqueue(IndexAction action) {
+  public void enqueue(ClusterAction action) {
     this.actions.add(action);
   }
 
+  private void enqueueActions(){
+    CountDownLatch latch = new CountDownLatch(actions.size());
+    for(ClusterAction action:actions){
+      action.setLatch(latch);
+      queue.enqueue(action);
+    }
+    try {
+      latch.await();
+    } catch (InterruptedException e) {
+      LOG.error("ES update has been interrupted: {}",e.getMessage());
+    }
+  }
+
   @Override
   public void commit() {
     session.commit();
-    queue.enqueue(actions);
+    enqueueActions();
   }
 
   @Override
   public void commit(boolean force) {
     session.commit(force);
-    queue.enqueue(actions);
+    enqueueActions();
   }
 
   /**
index d25a0110065164e92ecf72353c4308a1124bba36..3b5677fc9b90179452f1491a177be71f12e44f05 100644 (file)
 package org.sonar.core.rule;
 
 import com.google.common.collect.Lists;
-import org.apache.ibatis.session.ResultContext;
-import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.BatchComponent;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.rule.RuleKey;
-import org.sonar.core.db.BaseDao;
-import org.sonar.core.db.UnsuportedException;
-import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.MyBatis;
 
 import javax.annotation.CheckForNull;
 
-import java.sql.Timestamp;
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 
 import static com.google.common.collect.Lists.newArrayList;
 
-public class RuleDao extends BaseDao<RuleDto, RuleKey>
-  implements BatchComponent, ServerComponent {
+public class RuleDao implements BatchComponent, ServerComponent {
 
-  public RuleDao(MyBatis mybatis) {
-    super(mybatis);
-  }
-
-  @Override
-  protected String getIndexName() {
-    return RuleConstants.INDEX_NAME;
-  }
-
-  @Override
-  @CheckForNull
-  protected RuleDto doGetByKey(RuleKey key, SqlSession session) {
-    return getMapper(session).selectByKey(key);
-  }
-
-  @Override
-  protected RuleDto doInsert(RuleDto item, SqlSession session) {
-    session.getMapper(RuleMapper.class).insert(item);
-    return item;
-  }
-
-  @Override
-  protected RuleDto doUpdate(RuleDto item, SqlSession session) {
-    session.getMapper(RuleMapper.class).update(item);
-    return item;
-  }
-
-  @Override
-  protected void doDelete(RuleDto item, SqlSession session) {
-    throw new UnsuportedException("Rules cannot be deleted");
-  }
+  private MyBatis mybatis;
 
-  @Override
-  protected void doDeleteByKey(RuleKey key, SqlSession session) {
-    throw new UnsuportedException("Rules cannot be deleted");
+  public RuleDao(MyBatis mybatis) {
+    this.mybatis = mybatis;
   }
 
   public List<RuleDto> selectAll() {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectAll(session);
     } finally {
@@ -94,7 +55,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleDto> selectEnablesAndNonManual() {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectEnablesAndNonManual(session);
     } finally {
@@ -111,7 +72,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleDto> selectBySubCharacteristicId(Integer characteristicOrSubCharacteristicId) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectBySubCharacteristicId(characteristicOrSubCharacteristicId, session);
     } finally {
@@ -133,7 +94,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
 
   @CheckForNull
   public RuleDto selectById(Integer id) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectById(id, session);
     } finally {
@@ -146,10 +107,9 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
     return getMapper(session).selectByKey(ruleKey);
   }
 
-
   @CheckForNull
   public RuleDto selectByKey(RuleKey ruleKey) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectByKey(ruleKey, session);
     } finally {
@@ -159,7 +119,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
 
   @CheckForNull
   public RuleDto selectByName(String name) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return getMapper(session).selectByName(name);
     } finally {
@@ -167,8 +127,36 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
     }
   }
 
+  public void update(RuleDto rule, SqlSession session) {
+    getMapper(session).update(rule);
+  }
+
+  public void update(RuleDto rule) {
+    SqlSession session = mybatis.openSession();
+    try {
+      update(rule, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void insert(RuleDto ruleToInsert, SqlSession session) {
+    getMapper(session).insert(ruleToInsert);
+  }
+
+  public void insert(RuleDto ruleToInsert) {
+    SqlSession session = mybatis.openSession();
+    try {
+      insert(ruleToInsert, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
   public void insert(Collection<RuleDto> rules) {
-    DbSession session = mybatis.openSession(true);
+    SqlSession session = mybatis.openBatchSession();
     try {
       for (RuleDto rule : rules) {
         getMapper(session).batchInsert(rule);
@@ -179,12 +167,12 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
     }
   }
 
-  // ******************************
+  //******************************
   // Methods for Rule Parameters
-  // ******************************
+  //******************************
 
   public List<RuleParamDto> selectParameters() {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectParameters(session);
     } finally {
@@ -197,7 +185,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleParamDto> selectParametersByRuleId(Integer ruleId) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectParametersByRuleId(ruleId, session);
     } finally {
@@ -210,7 +198,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleParamDto> selectParametersByRuleIds(List<Integer> ruleIds) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectParametersByRuleIds(ruleIds, session);
     } finally {
@@ -232,7 +220,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public void insert(RuleParamDto param) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       insert(param, session);
       session.commit();
@@ -246,7 +234,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public void update(RuleParamDto param) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       update(param, session);
       session.commit();
@@ -264,9 +252,10 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
     return session.getMapper(RuleMapper.class);
   }
 
-  // ***************************
+  //***************************
   // Methods for Rule Tags
-  // ***************************
+  //***************************
+
 
   public void insert(RuleRuleTagDto newTag, SqlSession session) {
     getMapper(session).insertTag(newTag);
@@ -289,7 +278,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleRuleTagDto> selectTagsByRuleId(Integer ruleId) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectTagsByRuleIds(ruleId, session);
     } finally {
@@ -302,7 +291,7 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
   }
 
   public List<RuleRuleTagDto> selectTagsByRuleIds(List<Integer> ruleIds) {
-    SqlSession session = mybatis.openSession(false);
+    SqlSession session = mybatis.openSession();
     try {
       return selectTagsByRuleIds(ruleIds, session);
     } finally {
@@ -318,22 +307,4 @@ public class RuleDao extends BaseDao<RuleDto, RuleKey>
     }
     return dtos;
   }
-
-  @Override
-  public Collection<RuleKey> keysOfRowsUpdatedAfter(long timestamp) {
-    SqlSession session = mybatis.openSession(false);
-    try {
-      final List<RuleKey> keys = Lists.newArrayList();
-      session.select("selectKeysOfRulesUpdatedSince", new Timestamp(timestamp), new ResultHandler() {
-        @Override
-        public void handleResult(ResultContext context) {
-          Map<String, String> map = (Map) context.getResultObject();
-          keys.add(RuleKey.of(map.get("repo"), map.get("rule")));
-        }
-      });
-      return keys;
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
 }
index 3e3bc22abb50e0ab0d3b5af2b91e15279b7ef542..6386962c054ab7ce98a067f8e6d3c0ceca4b45ad 100644 (file)
@@ -32,7 +32,6 @@ import org.sonar.api.utils.DateUtils;
 import org.sonar.check.Cardinality;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 
-import java.util.Arrays;
 import java.util.List;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -372,33 +371,6 @@ public class RuleDaoTest extends AbstractDaoTestCase {
     assertThat(dao.selectTagsByRuleIds(newArrayList(3, 4))).hasSize(3);
   }
 
-  @Test
-  public void keysOfRowsUpdatedAfter() throws Exception {
-    setupData("empty");
-
-    RuleDto rule1 = new RuleDto()
-      .setId(1)
-      .setRepositoryKey("foo")
-      .setRuleKey("R1")
-      .setName("ROne")
-      .setCreatedAt(DateUtils.parseDate("2013-12-16"))
-      .setUpdatedAt(DateUtils.parseDate("2013-12-16"));
-    RuleDto rule2 = new RuleDto()
-      .setId(2)
-      .setRepositoryKey("foo")
-      .setRuleKey("R2")
-      .setName("RTwo")
-      .setCreatedAt(DateUtils.parseDate("2014-01-28"))
-      .setUpdatedAt(DateUtils.parseDate("2014-05-19"));
-    dao.insert(Arrays.asList(rule1, rule2));
-
-    assertThat(dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-06-01").getTime())).isEmpty();
-    assertThat(dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2012-01-01").getTime())).hasSize(2);
-    Iterable<RuleKey> keys = dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-05-17").getTime());
-    assertThat(keys).hasSize(1);
-    assertThat(Iterables.getFirst(keys, null).rule()).isEqualTo("R2");
-  }
-
   private List<Integer> idsFromRuleDtos(List<RuleDto> ruleDtos){
     return newArrayList(Iterables.transform(ruleDtos, new Function<RuleDto, Integer>() {
       @Override
index 0a6b282f7ec551fbde1b489bd837250dd16585a1..dc2e29f224780e2e455d015fd7286f691dccd574 100644 (file)
  */
 package org.sonar.server.cluster;
 
-import org.sonar.core.cluster.IndexAction;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.cluster.ClusterAction;
 import org.sonar.core.cluster.WorkQueue;
 
-import javax.annotation.CheckForNull;
-import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
-public class LocalNonBlockingWorkQueue implements WorkQueue {
+public class LocalNonBlockingWorkQueue extends LinkedBlockingQueue<Runnable>
+  implements ServerComponent, WorkQueue{
 
-  private final ConcurrentLinkedQueue<IndexAction<?>> actions = new ConcurrentLinkedQueue<IndexAction<?>>();
-
-  @Override
-  public void enqueue(IndexAction<?> indexAction) {
-    actions.offer(indexAction);
+  public LocalNonBlockingWorkQueue(){
+    super();
   }
 
   @Override
-  public void enqueue(Iterable<IndexAction<?>> indexActions) {
-    for (IndexAction<?> action : indexActions) {
-      enqueue(action);
+  public void enqueue(ClusterAction action) {
+    try {
+      this.offer(action, 1000,TimeUnit.SECONDS);
+    } catch (InterruptedException e) {
+      //TODO throw a runtime error here.
     }
   }
 
-  @CheckForNull
   @Override
-  public IndexAction<?> dequeue() {
-    IndexAction<?> out = actions.poll();
-    return out;
+  public void enqueue(Iterable<ClusterAction> actions) {
+    for (ClusterAction action : actions) {
+      enqueue(action);
+    }
   }
 }
index 57884afc6ce6960f058fa5cd962d72d024ff66db..1cbc2a9b44070ea1d5f88dd1dbe0c25af701311e 100644 (file)
  */
 package org.sonar.server.cluster;
 
-import org.jfree.util.Log;
 import org.picocontainer.Startable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
-import org.sonar.core.cluster.IndexAction;
-import org.sonar.core.cluster.WorkQueue;
 import org.sonar.server.search.Index;
+import org.sonar.server.search.IndexAction;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
-public class LocalQueueWorker implements ServerComponent, Startable {
+public class LocalQueueWorker extends ThreadPoolExecutor
+  implements ServerComponent, Startable {
 
-  private static final Logger LOG = LoggerFactory.getLogger(LocalNonBlockingWorkQueue.class);
+  private static final Logger LOG = LoggerFactory.getLogger(LocalQueueWorker.class);
 
-  private WorkQueue queue;
-
-  private volatile Thread worker;
   private Map<String, Index<?>> indexes;
 
-  class Worker implements Runnable {
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public void run() {
-      LOG.info("Starting Worker Thread");
-      Thread thisThread = Thread.currentThread();
-      while (worker == thisThread) {
-        try {
-          Thread.sleep(20);
-        } catch (InterruptedException e) {
-          Log.error("Oops");
-        }
+  public LocalQueueWorker(LocalNonBlockingWorkQueue queue, Index<?>... allIndexes) {
+    super(10, 10, 500l, TimeUnit.MILLISECONDS, queue);
 
-        @SuppressWarnings("rawtypes")
-        IndexAction action = queue.dequeue();
-
-        if (action != null && indexes.containsKey(action.getIndexName())) {
-          LOG.info("Dequeued action {}",action);
-          indexes.get(action.getIndexName()).executeAction(action);
-        }
-      }
-      LOG.info("Stoping Worker Thread");
+    // Save all instances of Index<?>
+    this.indexes = new HashMap<String, Index<?>>();
+    for (Index<?> index : allIndexes) {
+      this.indexes.put(index.getIndexName(), index);
     }
   }
 
-  public LocalQueueWorker(WorkQueue queue, Index<?>... indexes) {
-    this.queue = queue;
-    this.worker = new Thread(new Worker());
-    this.indexes = new HashMap<String, Index<?>>();
-    for(Index<?> index:indexes){
-      this.indexes.put(index.getIndexName(), index);
+  protected void beforeExecute(Thread t, Runnable r) {
+    LOG.debug("Starting task: {}",r);
+    super.beforeExecute(t, r);
+    if(r.getClass().isAssignableFrom(IndexAction.class)){
+      IndexAction<?> ia = (IndexAction<?>)r;
+      LOG.trace("Task is an IndexAction for {}",ia.getIndexName());
+      ia.setIndex(indexes.get(ia.getIndexName()));
     }
   }
 
+  protected void afterExecute(Runnable r, Throwable t) {
+    super.afterExecute(r, t);
+  }
 
   @Override
   public void start() {
-    this.worker.start();
+    this.prestartCoreThread();
   }
 
   @Override
   public void stop() {
-    this.worker = null;
+    this.shutdown();
   }
 }
diff --git a/sonar-server/src/main/java/org/sonar/server/db/BaseDao.java b/sonar-server/src/main/java/org/sonar/server/db/BaseDao.java
new file mode 100644 (file)
index 0000000..fd588c9
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.db;
+
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.core.db.Dao;
+import org.sonar.core.db.Dto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.search.IndexAction;
+
+import java.io.Serializable;
+
+public abstract class BaseDao<E extends Dto<K>, K extends Serializable>
+  implements Dao<E, K> {
+
+  protected MyBatis mybatis;
+
+  protected BaseDao(MyBatis myBatis) {
+    this.mybatis = myBatis;
+  }
+
+  protected abstract String getIndexName();
+
+  protected abstract E doGetByKey(K key, SqlSession session);
+
+  protected abstract E doInsert(E item, SqlSession session);
+
+  protected abstract E doUpdate(E item, SqlSession session);
+
+  protected abstract void doDelete(E item, SqlSession session);
+
+  protected abstract void doDeleteByKey(K key, SqlSession session);
+
+  protected MyBatis getMyBatis() {
+    return this.mybatis;
+  }
+
+  @Override
+  public E getByKey(K key) {
+    DbSession session = getMyBatis().openSession(false);
+    E item = this.doGetByKey(key, session);
+    MyBatis.closeQuietly(session);
+    return item;
+  }
+
+  @Override
+  public E update(E item, DbSession session) {
+    session.enqueue(new IndexAction(this.getIndexName(),
+      IndexAction.Method.UPDATE, item.getKey()));
+    return this.doUpdate(item, session);
+  }
+
+  @Override
+  public E update(E item) {
+    DbSession session = getMyBatis().openSession(false);
+    try {
+      this.update(item, session);
+      session.commit();
+      return item;
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @Override
+  public E insert(E item, DbSession session) {
+    IndexAction action = new IndexAction(this.getIndexName(),
+      IndexAction.Method.INSERT, item.getKey());
+    session.enqueue(action);
+    this.doInsert(item, session);
+    return item;
+  }
+
+  @Override
+  public E insert(E item) {
+    DbSession session = getMyBatis().openSession(false);
+    try {
+      this.insert(item, session);
+      session.commit();
+      return item;
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @Override
+  public void delete(E item, DbSession session) {
+    session.enqueue(new IndexAction(this.getIndexName(),
+      IndexAction.Method.DELETE, item.getKey()));
+    this.doDelete(item, session);
+  }
+
+  @Override
+  public void delete(E item) {
+    DbSession session = getMyBatis().openSession(false);
+    try {
+      this.delete(item, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @Override
+  public void deleteByKey(K key, DbSession session) {
+    session.enqueue(new IndexAction(this.getIndexName(),
+      IndexAction.Method.DELETE, key));
+    this.doDeleteByKey(key, session);
+  }
+
+  @Override
+  public void deleteByKey(K key) {
+    DbSession session = getMyBatis().openSession(false);
+    try {
+      this.doDeleteByKey(key, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+}
index b2fcfe87dcde37297f93701605447e0540afbe39..4b3521cac18255376dc2b92e6648b7aea3f36661 100644 (file)
  */
 package org.sonar.server.platform;
 
+import org.sonar.server.cluster.LocalNonBlockingWorkQueue;
+
+import org.sonar.server.rule2.RuleDao;
+import org.sonar.server.rule2.RuleService;
 import com.google.common.collect.Lists;
 import org.apache.commons.configuration.BaseConfiguration;
 import org.sonar.api.config.EmailSettings;
@@ -78,7 +82,6 @@ import org.sonar.jpa.session.DefaultDatabaseConnector;
 import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
 import org.sonar.server.authentication.ws.AuthenticationWs;
 import org.sonar.server.charts.ChartFactory;
-import org.sonar.server.cluster.LocalNonBlockingWorkQueue;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
@@ -170,7 +173,10 @@ class ServerComponents {
       SemaphoresImpl.class,
       TempFolderCleaner.class,
       new TempFolderProvider(),
-      System2.INSTANCE
+      System2.INSTANCE,
+
+      /* new RuleDao working with ES */
+      RuleDao.class
     ));
     components.addAll(CorePropertyDefinitions.all());
     components.addAll(DatabaseMigrations.CLASSES);
@@ -284,6 +290,7 @@ class ServerComponents {
     pico.addSingleton(AddTagsWsHandler.class);
     pico.addSingleton(RemoveTagsWsHandler.class);
     pico.addSingleton(RulesDefinitionXmlLoader.class);
+    pico.addSingleton(RuleService.class);
 
     // rule tags
     pico.addSingleton(ESRuleTags.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleDao.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleDao.java
new file mode 100644 (file)
index 0000000..87be472
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.rule2;
+
+import com.google.common.collect.Lists;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.db.UnsuportedException;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleConstants;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleMapper;
+import org.sonar.core.rule.RuleParamDto;
+import org.sonar.core.rule.RuleRuleTagDto;
+import org.sonar.server.db.BaseDao;
+
+import javax.annotation.CheckForNull;
+
+import java.sql.Timestamp;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class RuleDao extends BaseDao<RuleDto, RuleKey>
+  implements BatchComponent, ServerComponent {
+
+  public RuleDao(MyBatis mybatis) {
+    super(mybatis);
+  }
+
+  @Override
+  protected String getIndexName() {
+    return RuleConstants.INDEX_NAME;
+  }
+
+  @Override
+  @CheckForNull
+  protected RuleDto doGetByKey(RuleKey key, SqlSession session) {
+    return getMapper(session).selectByKey(key);
+  }
+
+  @Override
+  protected RuleDto doInsert(RuleDto item, SqlSession session) {
+    session.getMapper(RuleMapper.class).insert(item);
+    return item;
+  }
+
+  @Override
+  protected RuleDto doUpdate(RuleDto item, SqlSession session) {
+    session.getMapper(RuleMapper.class).update(item);
+    return item;
+  }
+
+  @Override
+  protected void doDelete(RuleDto item, SqlSession session) {
+    throw new UnsuportedException("Rules cannot be deleted");
+  }
+
+  @Override
+  protected void doDeleteByKey(RuleKey key, SqlSession session) {
+    throw new UnsuportedException("Rules cannot be deleted");
+  }
+
+  public List<RuleDto> selectAll() {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectAll(session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleDto> selectAll(SqlSession session) {
+    return getMapper(session).selectAll();
+  }
+
+  public List<RuleDto> selectEnablesAndNonManual() {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectEnablesAndNonManual(session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleDto> selectEnablesAndNonManual(SqlSession session) {
+    return getMapper(session).selectEnablesAndNonManual();
+  }
+
+  public List<RuleDto> selectNonManual(SqlSession session) {
+    return getMapper(session).selectNonManual();
+  }
+
+  public List<RuleDto> selectBySubCharacteristicId(Integer characteristicOrSubCharacteristicId) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectBySubCharacteristicId(characteristicOrSubCharacteristicId, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  /**
+   * Return all rules (even the REMOVED ones) linked on to a sub characteristic
+   */
+  public List<RuleDto> selectBySubCharacteristicId(Integer subCharacteristicId, SqlSession session) {
+    return getMapper(session).selectBySubCharacteristicId(subCharacteristicId);
+  }
+
+  @CheckForNull
+  public RuleDto selectById(Integer id, SqlSession session) {
+    return getMapper(session).selectById(id);
+  }
+
+  @CheckForNull
+  public RuleDto selectById(Integer id) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectById(id, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public RuleDto selectByKey(RuleKey ruleKey, SqlSession session) {
+    return getMapper(session).selectByKey(ruleKey);
+  }
+
+
+  @CheckForNull
+  public RuleDto selectByKey(RuleKey ruleKey) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectByKey(ruleKey, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public RuleDto selectByName(String name) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return getMapper(session).selectByName(name);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void insert(Collection<RuleDto> rules) {
+    DbSession session = mybatis.openSession(true);
+    try {
+      for (RuleDto rule : rules) {
+        getMapper(session).batchInsert(rule);
+      }
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  // ******************************
+  // Methods for Rule Parameters
+  // ******************************
+
+  public List<RuleParamDto> selectParameters() {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectParameters(session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleParamDto> selectParameters(SqlSession session) {
+    return getMapper(session).selectAllParams();
+  }
+
+  public List<RuleParamDto> selectParametersByRuleId(Integer ruleId) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectParametersByRuleId(ruleId, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleParamDto> selectParametersByRuleId(Integer ruleId, SqlSession session) {
+    return selectParametersByRuleIds(newArrayList(ruleId));
+  }
+
+  public List<RuleParamDto> selectParametersByRuleIds(List<Integer> ruleIds) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectParametersByRuleIds(ruleIds, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleParamDto> selectParametersByRuleIds(List<Integer> ruleIds, SqlSession session) {
+    List<RuleParamDto> dtos = newArrayList();
+    List<List<Integer>> partitionList = Lists.partition(newArrayList(ruleIds), 1000);
+    for (List<Integer> partition : partitionList) {
+      dtos.addAll(getMapper(session).selectParamsByRuleIds(partition));
+    }
+    return dtos;
+  }
+
+  public void insert(RuleParamDto param, SqlSession session) {
+    getMapper(session).insertParameter(param);
+  }
+
+  public void insert(RuleParamDto param) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      insert(param, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void update(RuleParamDto param, SqlSession session) {
+    getMapper(session).updateParameter(param);
+  }
+
+  public void update(RuleParamDto param) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      update(param, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public RuleParamDto selectParamByRuleAndKey(Integer ruleId, String key, SqlSession session) {
+    return getMapper(session).selectParamByRuleAndKey(ruleId, key);
+  }
+
+  private RuleMapper getMapper(SqlSession session) {
+    return session.getMapper(RuleMapper.class);
+  }
+
+  // ***************************
+  // Methods for Rule Tags
+  // ***************************
+
+  public void insert(RuleRuleTagDto newTag, SqlSession session) {
+    getMapper(session).insertTag(newTag);
+  }
+
+  public void deleteParam(RuleParamDto persistedParam, SqlSession sqlSession) {
+    getMapper(sqlSession).deleteParameter(persistedParam.getId());
+  }
+
+  public void deleteTag(RuleRuleTagDto tagToDelete, SqlSession session) {
+    getMapper(session).deleteTag(tagToDelete.getId().intValue());
+  }
+
+  public void update(RuleRuleTagDto existingTag, SqlSession session) {
+    getMapper(session).updateTag(existingTag);
+  }
+
+  public List<RuleRuleTagDto> selectTags(SqlSession session) {
+    return getMapper(session).selectAllTags();
+  }
+
+  public List<RuleRuleTagDto> selectTagsByRuleId(Integer ruleId) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectTagsByRuleIds(ruleId, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleRuleTagDto> selectTagsByRuleIds(Integer ruleId, SqlSession session) {
+    return selectTagsByRuleIds(newArrayList(ruleId), session);
+  }
+
+  public List<RuleRuleTagDto> selectTagsByRuleIds(List<Integer> ruleIds) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      return selectTagsByRuleIds(ruleIds, session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<RuleRuleTagDto> selectTagsByRuleIds(List<Integer> ruleIds, SqlSession session) {
+    List<RuleRuleTagDto> dtos = newArrayList();
+    List<List<Integer>> partitionList = Lists.partition(newArrayList(ruleIds), 1000);
+    for (List<Integer> partition : partitionList) {
+      dtos.addAll(getMapper(session).selectTagsByRuleIds(partition));
+    }
+    return dtos;
+  }
+
+  @Override
+  public Collection<RuleKey> keysOfRowsUpdatedAfter(long timestamp) {
+    SqlSession session = mybatis.openSession(false);
+    try {
+      final List<RuleKey> keys = Lists.newArrayList();
+      session.select("selectKeysOfRulesUpdatedSince", new Timestamp(timestamp), new ResultHandler() {
+        @Override
+        public void handleResult(ResultContext context) {
+          Map<String, String> map = (Map) context.getResultObject();
+          keys.add(RuleKey.of(map.get("repo"), map.get("rule")));
+        }
+      });
+      return keys;
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java
new file mode 100644 (file)
index 0000000..c3633d3
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.rule2;
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+import org.sonar.server.search.Hit;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RuleImpl implements Rule {
+
+  private Map<String, Object> fields;
+
+  public RuleImpl(){
+    this.fields = new HashMap<String, Object>();
+  }
+
+  private RuleImpl(Map<String, Object> fields){
+    this.fields = fields;
+  }
+
+  @Override
+  public RuleKey key() {
+    return RuleKey.of((String)this.fields.get("repositoryKey"),
+      (String)this.fields.get("ruleKey"));
+  }
+
+  @Override
+  public String language() {
+    return (String) this.fields.get("language");
+  }
+
+  @Override
+  public String name() {
+    return (String) this.fields.get("name");
+  }
+
+  @Override
+  public String description() {
+    return (String) this.fields.get("description");
+  }
+
+  @Override
+  public Severity severity() {
+    //FIXME missign Severity.of(String) or Severity.of(int);
+    return null;
+  }
+
+  @Override
+  public String status() {
+    return (String) this.fields.get("status");
+  }
+
+  @Override
+  public boolean template() {
+    //FIXME missign information in map.
+    return false;
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public List<String> tags() {
+    return (List<String>) this.fields.get("tags");
+  }
+
+  @Override
+  public List<RuleParam> params() {
+    //FIXME not yet Implemented in ES
+    return Collections.emptyList();
+  }
+
+  @Override
+  public String debtCharacteristicKey() {
+    return (String) this.fields.get("debtCharacteristicKey");
+  }
+
+  @Override
+  public String debtSubCharacteristicKey() {
+    return (String) this.fields.get("debtSubCharacteristicKey");
+  }
+
+  @Override
+  public DebtRemediationFunction debtRemediationFunction() {
+    //FIXME how to construct from string "defaultRemediationFunction"
+    return null;
+  }
+
+  @Override
+  public Date createdAt() {
+    return (Date) this.fields.get("createdAt");
+  }
+
+  @Override
+  public Date updatedAt() {
+    return (Date) this.fields.get("updatedAt");
+  }
+
+  public static Rule fromHit(Hit hit) {
+    return new RuleImpl(hit.getFields());
+  }
+
+}
index 6d6fd7e0036f6f29a53ae75daa0a220b916d861e..229d65bc2b02bf0111c2e0506ed5ed293b6cf0d0 100644 (file)
@@ -19,8 +19,6 @@
  */
 package org.sonar.server.rule2;
 
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleDao;
 import org.apache.commons.beanutils.BeanUtils;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.slf4j.Logger;
@@ -28,8 +26,10 @@ import org.slf4j.LoggerFactory;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.cluster.WorkQueue;
 import org.sonar.core.profiling.Profiling;
+import org.sonar.core.qualityprofile.db.ActiveRuleDao;
+import org.sonar.core.qualityprofile.db.ActiveRuleDto;
 import org.sonar.core.rule.RuleConstants;
-import org.sonar.core.rule.RuleDao;
+import org.sonar.server.rule2.RuleDao;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.server.es.ESNode;
 import org.sonar.server.search.BaseIndex;
@@ -47,8 +47,8 @@ public class RuleIndex extends BaseIndex<RuleKey, RuleDto> {
 
   private ActiveRuleDao activeRuleDao;
 
-  public RuleIndex(WorkQueue queue, RuleDao dao, ActiveRuleDao ActiveRuleDao, Profiling profiling, ESNode node) {
-    super(queue, dao, profiling, node);
+  public RuleIndex(WorkQueue workQueue, RuleDao dao, ActiveRuleDao ActiveRuleDao, Profiling profiling, ESNode node) {
+    super(workQueue, dao, profiling, node);
     this.activeRuleDao = ActiveRuleDao;
   }
 
@@ -157,10 +157,7 @@ public class RuleIndex extends BaseIndex<RuleKey, RuleDto> {
 
     try {
 
-      long start = System.currentTimeMillis();
       RuleDto rule = dao.getByKey(key);
-      LOG.info("Action dao.getByKey(key) in {} took {}ms",
-        this.getIndexName(), (System.currentTimeMillis() - start));
 
       XContentBuilder document = jsonBuilder().startObject();
 
@@ -171,8 +168,6 @@ public class RuleIndex extends BaseIndex<RuleKey, RuleDto> {
         document.field(property.getKey(), property.getValue());
       }
 
-      start = System.currentTimeMillis();
-
       document.startArray("active");
       for (ActiveRuleDto activeRule : activeRuleDao.selectByRuleId(rule.getId())) {
         document.startObject();
@@ -185,9 +180,6 @@ public class RuleIndex extends BaseIndex<RuleKey, RuleDto> {
       }
       document.endArray();
 
-      LOG.info("Action activeRuleDao.selectByRuleId(rule.getId()) in {} took {}ms",
-        this.getIndexName(), (System.currentTimeMillis() - start));
-
       return document.endObject();
     } catch (IOException e) {
       LOG.error("Could not normalize {} in {} because {}",
index c712d96d2a572460c3db035926e2f084942b4ece..ad8853d6599a8408b0947bf15d9c5337e4e7c323 100644 (file)
@@ -22,12 +22,16 @@ package org.sonar.server.rule2;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
 import org.sonar.server.search.Hit;
 import org.sonar.server.search.QueryOptions;
 import org.sonar.server.search.Results;
 
 import javax.annotation.CheckForNull;
 
+import java.util.Collection;
+import java.util.Collections;
+
 /**
  * @since 4.4
  */
@@ -53,4 +57,16 @@ public class RuleService implements ServerComponent {
   public Results search(RuleQuery query, QueryOptions options) {
     throw new UnsupportedOperationException("TODO");
   }
+
+  public Collection<Hit> search(RuleQuery query) {
+    return Collections.emptyList();
+  }
+
+  public static Rule toRule(RuleDto ruleDto) {
+    return new RuleImpl();
+  }
+
+  public static Rule toRule(Hit hit) {
+    return RuleImpl.fromHit(hit);
+  }
 }
index 727246c4689f5942a70edd97f3bb7d927ad271b0..e7916ca6402ee3bea6d490db2716d900ffb663df 100644 (file)
@@ -31,8 +31,8 @@ import org.elasticsearch.client.Client;
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonar.core.cluster.IndexAction;
-import org.sonar.core.cluster.IndexAction.Method;
+import org.sonar.server.search.IndexAction;
+import org.sonar.server.search.IndexAction.Method;
 import org.sonar.core.cluster.WorkQueue;
 import org.sonar.core.db.Dao;
 import org.sonar.core.db.Dto;
@@ -58,14 +58,12 @@ public abstract class BaseIndex<K extends Serializable, E extends Dto<K>> implem
   private final Profiling profiling;
   private Client client;
   private final ESNode node;
-  private WorkQueue workQueue;
   private IndexSynchronizer<K> synchronizer;
   protected Dao<E, K> dao;
 
   public BaseIndex(WorkQueue workQueue, Dao<E, K> dao, Profiling profiling, ESNode node) {
     this.profiling = profiling;
-    this.workQueue = workQueue;
-    this.synchronizer = new IndexSynchronizer<K>(this, dao, this.workQueue);
+    this.synchronizer = new IndexSynchronizer<K>(this, dao, workQueue);
     this.dao = dao;
     this.node = node;
   }
@@ -167,8 +165,7 @@ public abstract class BaseIndex<K extends Serializable, E extends Dto<K>> implem
   /* Index Action Methods */
 
   @Override
-  public void executeAction(IndexAction<K> action) {
-    StopWatch watch = this.createWatch();
+  public boolean executeAction(IndexAction<K> action) {
     long start = System.currentTimeMillis();
     if (action.getMethod().equals(Method.DELETE)) {
       this.delete(action.getKey());
@@ -177,9 +174,9 @@ public abstract class BaseIndex<K extends Serializable, E extends Dto<K>> implem
     } else if (action.getMethod().equals(Method.UPDATE)) {
       this.update(action.getKey());
     }
-    LOG.info("Action {} in {} took {}ms", action.getMethod(),
+    LOG.debug("Action {} in {} took {}ms", action.getMethod(),
       this.getIndexName(), (System.currentTimeMillis() - start));
-    watch.stop("Action {} in {}", action.getMethod(), this.getIndexName());
+    return true;
   }
 
   /* Index management methods */
@@ -207,7 +204,7 @@ public abstract class BaseIndex<K extends Serializable, E extends Dto<K>> implem
       XContentBuilder doc = this.normalize(key);
       String keyvalue = this.getKeyValue(key);
       if (doc != null && keyvalue != null && !keyvalue.isEmpty()) {
-        LOG.info("Update document with key {}", key);
+        LOG.debug("Update document with key {}", key);
         IndexResponse result = getClient().index(
           new IndexRequest(this.getIndexName(),
             this.getType(), keyvalue)
index 6a45b550ddea4ae4d5e4ebcbc3f1c2f005b63e75..d0046510e7970950b7e9aedfdb885ff17facfc49 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.search;
 
 import org.elasticsearch.common.xcontent.XContentBuilder;
 import org.picocontainer.Startable;
-import org.sonar.core.cluster.IndexAction;
 
 import javax.annotation.CheckForNull;
 import java.io.Serializable;
@@ -30,7 +29,7 @@ public interface Index<K extends Serializable> extends Startable {
 
   String getIndexName();
 
-  void executeAction(IndexAction<K> action);
+  boolean executeAction(IndexAction<K> action);
 
   @CheckForNull
   Hit getByKey(K key);
diff --git a/sonar-server/src/main/java/org/sonar/server/search/IndexAction.java b/sonar-server/src/main/java/org/sonar/server/search/IndexAction.java
new file mode 100644 (file)
index 0000000..c882941
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.search;
+
+import org.sonar.core.cluster.ClusterAction;
+
+import java.io.Serializable;
+
+public class IndexAction<K extends Serializable> extends ClusterAction {
+
+  public enum Method {
+    INSERT, UPDATE, DELETE
+  }
+
+  private String indexName;
+  private K key;
+  private Method method;
+  private Index<K> index;
+
+
+  public IndexAction(String indexName, Method method, K key){
+    super();
+    this.indexName = indexName;
+    this.method = method;
+    this.key = key;
+  }
+
+  public Method getMethod(){
+    return this.method;
+  }
+
+  public String getIndexName() {
+    return indexName;
+  }
+
+  public void setIndexName(String indexName) {
+    this.indexName = indexName;
+  }
+
+  public K getKey() {
+    return key;
+  }
+
+  public void setKey(K key) {
+    this.key = key;
+  }
+
+  public void setMethod(Method method) {
+    this.method = method;
+  }
+
+  @Override
+  public void doExecute() {
+    index.executeAction(this);
+  }
+
+  @SuppressWarnings("unchecked")
+  public void setIndex(Index<?> index) {
+    this.index = (Index<K>) index;
+  }
+
+  @Override
+  public String toString(){
+    return "{IndexAction {key: " + getKey()+"}";
+  }
+}
index 0371e5309ad37bc1ffbad82d2a57289cc3bf6960..56ae2f4b8e99113f861f07e2e18ce95ea44a4479 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.search;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonar.core.cluster.IndexAction;
 import org.sonar.core.cluster.WorkQueue;
 import org.sonar.core.db.Dao;
 
@@ -52,7 +51,7 @@ public class IndexSynchronizer<K extends Serializable> {
       if (LOG.isTraceEnabled()) {
         LOG.trace("Adding {} to workQueue for {}", key, index.getClass().getSimpleName());
       }
-      workQueue.enqueue(new IndexAction(index.getIndexName(), IndexAction.Method.INSERT, key));
+      workQueue.enqueue(new IndexAction<K>(index.getIndexName(), IndexAction.Method.INSERT, key));
     }
 
     return this;
index 39a65b0c0a4617564171175e12d72bd0e9696f38..6680efacd8403cbd3bfbb159aa70ec1581e57965 100644 (file)
 package org.sonar.server.search;
 
 import com.google.common.collect.ImmutableList;
-
-import org.sonar.server.rule2.RuleIndex;
 import org.sonar.server.cluster.LocalQueueWorker;
+import org.sonar.server.rule2.RuleIndex;
 
 import java.util.List;
 
 public final class IndexUtils {
 
-  private IndexUtils() {
-  }
 
   @SuppressWarnings("unchecked")
   public static List<Class> getIndexClasses() {
diff --git a/sonar-server/src/test/java/org/sonar/server/cluster/LocalNonBlockingWorkQueueTest.java b/sonar-server/src/test/java/org/sonar/server/cluster/LocalNonBlockingWorkQueueTest.java
deleted file mode 100644 (file)
index 74b2b9f..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.cluster;
-
-import org.sonar.core.cluster.IndexAction;
-import org.junit.Test;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class LocalNonBlockingWorkQueueTest {
-
-  private static final String WORKING_IDNEX = "working_index";
-
-  @Test
-  public void test_enqueue_dequeue_indexAction(){
-    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
-    queue.enqueue(new IndexAction(WORKING_IDNEX, IndexAction.Method.INSERT,new Integer(33)));
-    IndexAction action = queue.dequeue();
-    assertThat(action.getIndexName()).isEqualTo(WORKING_IDNEX);
-    assertThat(action.getKey()).isEqualTo(new Integer(33));
-  }
-
-  @Test
-  public void test_enqueue_dequeue_to_null(){
-    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
-    queue.enqueue(new IndexAction<Integer>(WORKING_IDNEX, IndexAction.Method.INSERT,new Integer(33)));
-    queue.enqueue(new IndexAction(WORKING_IDNEX, IndexAction.Method.INSERT,new Integer(33)));
-    assertThat(queue.dequeue()).isNotNull();
-    assertThat(queue.dequeue()).isNotNull();
-    assertThat(queue.dequeue()).isNull();
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/cluster/LocalQueueWorkerTest.java b/sonar-server/src/test/java/org/sonar/server/cluster/LocalQueueWorkerTest.java
deleted file mode 100644 (file)
index abe89bb..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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 this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-package org.sonar.server.cluster;
-
-import org.sonar.core.cluster.IndexAction;
-import org.junit.Test;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class LocalQueueWorkerTest {
-
-  private static final String WORKING_IDNEX = "working_index";
-
-  @Test
-  public void test_worker_dequeue(){
-    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
-    LocalQueueWorker worker = new LocalQueueWorker(queue);
-    worker.start();
-    queue.enqueue(new IndexAction(WORKING_IDNEX, IndexAction.Method.INSERT,new Integer(33)));
-    queue.enqueue(new IndexAction(WORKING_IDNEX, IndexAction.Method.INSERT,new Integer(33)));
-    try {
-      Thread.sleep(500);
-    } catch (InterruptedException e) {
-      // TODO Auto-generated catch block
-      e.printStackTrace();
-    }
-    assertThat(queue.dequeue()).isNull();
-    queue = null;
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/RuleDaoTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/RuleDaoTest.java
new file mode 100644 (file)
index 0000000..704b3c6
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+package org.sonar.server.rule2;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.check.Cardinality;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.rule.RuleParamDto;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RuleDaoTest extends AbstractDaoTestCase {
+
+  private static RuleDao dao;
+
+  @Before
+  public void createDao() throws Exception {
+    dao = new RuleDao(getMyBatis());
+  }
+
+  @Test
+  public void select_all() throws Exception {
+    setupData("selectAll");
+    List<RuleDto> ruleDtos = dao.selectAll();
+
+    assertThat(ruleDtos).hasSize(1);
+
+    RuleDto ruleDto = ruleDtos.get(0);
+    assertThat(ruleDto.getId()).isEqualTo(1);
+    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
+    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
+    assertThat(ruleDto.getStatus()).isEqualTo(Rule.STATUS_READY);
+    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
+    assertThat(ruleDto.getNoteData()).isEqualTo("Rule note with accents \u00e9\u00e8\u00e0");
+    assertThat(ruleDto.getSubCharacteristicId()).isEqualTo(100);
+    assertThat(ruleDto.getDefaultSubCharacteristicId()).isEqualTo(101);
+    assertThat(ruleDto.getRemediationFunction()).isEqualTo("linear");
+    assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("linear_offset");
+    assertThat(ruleDto.getRemediationCoefficient()).isEqualTo("1h");
+    assertThat(ruleDto.getDefaultRemediationCoefficient()).isEqualTo("5d");
+    assertThat(ruleDto.getRemediationOffset()).isEqualTo("5min");
+    assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("10h");
+    assertThat(ruleDto.getEffortToFixDescription()).isEqualTo("squid.S115.effortToFix");
+  }
+
+  @Test
+  public void select_enables_and_non_manual() throws Exception {
+    setupData("select_enables_and_non_manual");
+    List<RuleDto> ruleDtos = dao.selectEnablesAndNonManual();
+
+    assertThat(ruleDtos.size()).isEqualTo(1);
+    RuleDto ruleDto = ruleDtos.get(0);
+    assertThat(ruleDto.getId()).isEqualTo(1);
+    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
+    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
+    assertThat(ruleDto.getStatus()).isEqualTo(Rule.STATUS_READY);
+    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
+    assertThat(ruleDto.getNoteData()).isEqualTo("Rule note with accents \u00e9\u00e8\u00e0");
+    assertThat(ruleDto.getSubCharacteristicId()).isEqualTo(100);
+    assertThat(ruleDto.getDefaultSubCharacteristicId()).isEqualTo(101);
+    assertThat(ruleDto.getRemediationFunction()).isEqualTo("LINEAR");
+    assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
+    assertThat(ruleDto.getRemediationCoefficient()).isEqualTo("1h");
+    assertThat(ruleDto.getDefaultRemediationCoefficient()).isEqualTo("5d");
+    assertThat(ruleDto.getRemediationOffset()).isEqualTo("5min");
+    assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("10h");
+    assertThat(ruleDto.getEffortToFixDescription()).isEqualTo("squid.S115.effortToFix");
+  }
+
+  @Test
+  public void select_by_id() throws Exception {
+    setupData("selectById");
+    RuleDto ruleDto = dao.selectById(2);
+
+    assertThat(ruleDto.getId()).isEqualTo(2);
+    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
+    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
+    assertThat(ruleDto.getStatus()).isEqualTo(Rule.STATUS_READY);
+    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
+  }
+
+  @Test
+  public void select_by_rule_key() throws Exception {
+    setupData("select_by_rule_key");
+    assertThat(dao.selectByKey(RuleKey.of("checkstyle", "AvoidComparison"))).isNotNull();
+    assertThat(dao.selectByKey(RuleKey.of("checkstyle", "Unknown"))).isNull();
+    assertThat(dao.selectByKey(RuleKey.of("Unknown", "AvoidComparison"))).isNull();
+  }
+
+  @Test
+  public void select_by_name() throws Exception {
+    setupData("select_by_name");
+    RuleDto ruleDto = dao.selectByName("Avoid Null");
+
+    assertThat(ruleDto.getId()).isEqualTo(2);
+    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
+    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
+    assertThat(ruleDto.getStatus()).isEqualTo(Rule.STATUS_READY);
+    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
+  }
+
+  @Test
+  public void select_non_manual() throws Exception {
+    setupData("selectNonManual");
+    SqlSession session = getMyBatis().openSession();
+    List<RuleDto> ruleDtos = dao.selectNonManual(session);
+    session.commit();
+    session.close();
+
+    assertThat(ruleDtos.size()).isEqualTo(1);
+    RuleDto ruleDto = ruleDtos.get(0);
+    assertThat(ruleDto.getId()).isEqualTo(1);
+    assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
+    assertThat(ruleDto.getDescription()).isEqualTo("Should avoid NULL");
+    assertThat(ruleDto.getStatus()).isEqualTo(Rule.STATUS_READY);
+    assertThat(ruleDto.getRepositoryKey()).isEqualTo("checkstyle");
+  }
+
+  @Test
+  public void select_by_sub_characteristic_id(){
+    setupData("select_by_sub_characteristic_id");
+
+    // Rules from sub characteristic (even REMOVED ones are returned)
+    List<RuleDto> ruleDtos = dao.selectBySubCharacteristicId(3);
+    assertThat(ruleDtos).hasSize(3);
+    assertThat(idsFromRuleDtos(ruleDtos)).containsExactly(2, 4, 5);
+
+    // Nothing on root characteristic
+    ruleDtos = dao.selectBySubCharacteristicId(1);
+    assertThat(ruleDtos).isEmpty();
+
+    // Rules from disabled characteristic
+    ruleDtos = dao.selectBySubCharacteristicId(11);
+    assertThat(idsFromRuleDtos(ruleDtos)).containsExactly(3);
+  }
+
+  @Test
+  public void update() {
+    setupData("update");
+
+    RuleDto ruleToUpdate = new RuleDto()
+      .setId(1)
+      .setRuleKey("NewRuleKey")
+      .setRepositoryKey("plugin")
+      .setName("new name")
+      .setDescription("new description")
+      .setStatus(Rule.STATUS_DEPRECATED)
+      .setConfigKey("NewConfigKey")
+      .setSeverity(Severity.INFO)
+      .setCardinality(Cardinality.MULTIPLE)
+      .setLanguage("dart")
+      .setParentId(3)
+      .setNoteData("My note")
+      .setNoteUserLogin("admin")
+      .setNoteCreatedAt(DateUtils.parseDate("2013-12-19"))
+      .setNoteUpdatedAt(DateUtils.parseDate("2013-12-20"))
+      .setSubCharacteristicId(100)
+      .setDefaultSubCharacteristicId(101)
+      .setRemediationFunction("linear")
+      .setDefaultRemediationFunction("linear_offset")
+      .setRemediationCoefficient("1h")
+      .setDefaultRemediationCoefficient("5d")
+      .setRemediationOffset("5min")
+      .setDefaultRemediationOffset("10h")
+      .setEffortToFixDescription("squid.S115.effortToFix")
+      .setUpdatedAt(DateUtils.parseDate("2013-12-17"));
+
+    dao.update(ruleToUpdate);
+
+    checkTables("update", "rules");
+  }
+
+  @Test
+  public void insert() {
+    setupData("empty");
+
+    RuleDto ruleToInsert = new RuleDto()
+      .setId(1)
+      .setRuleKey("NewRuleKey")
+      .setRepositoryKey("plugin")
+      .setName("new name")
+      .setDescription("new description")
+      .setStatus(Rule.STATUS_DEPRECATED)
+      .setConfigKey("NewConfigKey")
+      .setSeverity(Severity.INFO)
+      .setCardinality(Cardinality.MULTIPLE)
+      .setLanguage("dart")
+      .setParentId(3)
+      .setSubCharacteristicId(100)
+      .setDefaultSubCharacteristicId(101)
+      .setRemediationFunction("linear")
+      .setDefaultRemediationFunction("linear_offset")
+      .setRemediationCoefficient("1h")
+      .setDefaultRemediationCoefficient("5d")
+      .setRemediationOffset("5min")
+      .setDefaultRemediationOffset("10h")
+      .setEffortToFixDescription("squid.S115.effortToFix")
+      .setCreatedAt(DateUtils.parseDate("2013-12-16"))
+      .setUpdatedAt(DateUtils.parseDate("2013-12-17"));
+
+    dao.insert(ruleToInsert);
+
+    checkTables("insert", "rules");
+  }
+
+  @Test
+  public void insert_all() {
+    setupData("empty");
+
+    RuleDto ruleToInsert1 = new RuleDto()
+      .setId(1)
+      .setRuleKey("NewRuleKey")
+      .setRepositoryKey("plugin")
+      .setName("new name")
+      .setDescription("new description")
+      .setStatus(Rule.STATUS_DEPRECATED)
+      .setConfigKey("NewConfigKey")
+      .setSeverity(Severity.INFO)
+      .setCardinality(Cardinality.MULTIPLE)
+      .setLanguage("dart")
+      .setParentId(3)
+      .setSubCharacteristicId(100)
+      .setDefaultSubCharacteristicId(101)
+      .setRemediationFunction("linear")
+      .setDefaultRemediationFunction("linear_offset")
+      .setRemediationCoefficient("1h")
+      .setDefaultRemediationCoefficient("5d")
+      .setRemediationOffset("5min")
+      .setDefaultRemediationOffset("10h")
+      .setEffortToFixDescription("squid.S115.effortToFix")
+      .setCreatedAt(DateUtils.parseDate("2013-12-16"))
+      .setUpdatedAt(DateUtils.parseDate("2013-12-17"));
+
+    RuleDto ruleToInsert2 = new RuleDto()
+      .setId(2)
+      .setRuleKey("NewRuleKey2")
+      .setRepositoryKey("plugin2")
+      .setName("new name2")
+      .setDescription("new description2")
+      .setStatus(Rule.STATUS_BETA)
+      .setConfigKey("NewConfigKey2")
+      .setSeverity(Severity.MAJOR)
+      .setCardinality(Cardinality.SINGLE)
+      .setLanguage("js")
+      .setParentId(null)
+      .setSubCharacteristicId(102)
+      .setDefaultSubCharacteristicId(103)
+      .setRemediationFunction("linear_offset")
+      .setDefaultRemediationFunction("linear")
+      .setRemediationCoefficient("5d")
+      .setDefaultRemediationCoefficient("1h")
+      .setRemediationOffset("10h")
+      .setDefaultRemediationOffset("5min")
+      .setEffortToFixDescription("squid.S115.effortToFix2")
+      .setCreatedAt(DateUtils.parseDate("2013-12-14"))
+      .setUpdatedAt(DateUtils.parseDate("2013-12-15"));
+
+    dao.insert(ImmutableList.of(ruleToInsert1, ruleToInsert2));
+
+    checkTables("insert_all", "rules");
+  }
+
+  @Test
+  public void select_parameters() throws Exception {
+    setupData("selectParameters");
+    List<RuleParamDto> ruleDtos = dao.selectParameters();
+
+    assertThat(ruleDtos.size()).isEqualTo(1);
+    RuleParamDto ruleDto = ruleDtos.get(0);
+    assertThat(ruleDto.getId()).isEqualTo(1);
+    assertThat(ruleDto.getName()).isEqualTo("myParameter");
+    assertThat(ruleDto.getDescription()).isEqualTo("My Parameter");
+    assertThat(ruleDto.getType()).isEqualTo("plop");
+    assertThat(ruleDto.getDefaultValue()).isEqualTo("plouf");
+  }
+
+  @Test
+  public void select_parameters_by_rule_id() throws Exception {
+    setupData("select_parameters_by_rule_id");
+    int ruleId = 1;
+    List<RuleParamDto> ruleDtos = dao.selectParametersByRuleId(ruleId);
+
+    assertThat(ruleDtos.size()).isEqualTo(1);
+    RuleParamDto ruleDto = ruleDtos.get(0);
+    assertThat(ruleDto.getId()).isEqualTo(1);
+    assertThat(ruleDto.getName()).isEqualTo("myParameter");
+    assertThat(ruleDto.getDescription()).isEqualTo("My Parameter");
+    assertThat(ruleDto.getType()).isEqualTo("plop");
+    assertThat(ruleDto.getRuleId()).isEqualTo(ruleId);
+  }
+
+  @Test
+  public void select_parameters_by_rule_ids() throws Exception {
+    setupData("select_parameters_by_rule_ids");
+
+    assertThat(dao.selectParametersByRuleIds(newArrayList(1, 2))).hasSize(2);
+    assertThat(dao.selectParametersByRuleIds(newArrayList(1))).hasSize(1);
+  }
+
+  @Test
+  public void insert_parameter() {
+    setupData("insert_parameter");
+
+    RuleParamDto param = new RuleParamDto()
+      .setRuleId(1)
+      .setName("max")
+      .setType("INTEGER")
+      .setDefaultValue("30")
+      .setDescription("My Parameter");
+
+    dao.insert(param);
+
+    checkTables("insert_parameter", "rules_parameters");
+  }
+
+  @Test
+  public void update_parameter() {
+    setupData("update_parameter");
+
+    RuleParamDto param = new RuleParamDto()
+      .setId(1)
+      .setName("format")
+      .setType("STRING")
+      .setDefaultValue("^[a-z]+(\\.[a-z][a-z0-9]*)*$")
+      .setDescription("Regular expression used to check the package names against.");
+
+    dao.update(param);
+
+    checkTables("update_parameter", "rules_parameters");
+  }
+
+  @Test
+  public void select_tags_by_rule_id() throws Exception {
+    setupData("select_tags_by_rule_id");
+
+    assertThat(dao.selectTagsByRuleId(3)).hasSize(2);
+  }
+
+  @Test
+  public void select_tags_by_rule_ids() throws Exception {
+    setupData("select_tags_by_rule_ids");
+
+    assertThat(dao.selectTagsByRuleIds(newArrayList(3, 4))).hasSize(3);
+  }
+
+  @Test
+  public void keysOfRowsUpdatedAfter() throws Exception {
+    setupData("empty");
+
+    RuleDto rule1 = new RuleDto()
+      .setId(1)
+      .setRepositoryKey("foo")
+      .setRuleKey("R1")
+      .setName("ROne")
+      .setCreatedAt(DateUtils.parseDate("2013-12-16"))
+      .setUpdatedAt(DateUtils.parseDate("2013-12-16"));
+    RuleDto rule2 = new RuleDto()
+      .setId(2)
+      .setRepositoryKey("foo")
+      .setRuleKey("R2")
+      .setName("RTwo")
+      .setCreatedAt(DateUtils.parseDate("2014-01-28"))
+      .setUpdatedAt(DateUtils.parseDate("2014-05-19"));
+    dao.insert(Arrays.asList(rule1, rule2));
+
+    assertThat(dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-06-01").getTime())).isEmpty();
+    assertThat(dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2012-01-01").getTime())).hasSize(2);
+    Iterable<RuleKey> keys = dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-05-17").getTime());
+    assertThat(keys).hasSize(1);
+    assertThat(Iterables.getFirst(keys, null).rule()).isEqualTo("R2");
+  }
+
+  private List<Integer> idsFromRuleDtos(List<RuleDto> ruleDtos){
+    return newArrayList(Iterables.transform(ruleDtos, new Function<RuleDto, Integer>() {
+      @Override
+      public Integer apply(RuleDto input) {
+        return input.getId();
+      }
+    }));
+  }
+}
index de48aaa602206f9d46ebfaabf8c88472ba23cfa4..819bbb681777bfd3ea1ede275c65d86a0f37d989 100644 (file)
  */
 package org.sonar.server.rule2;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.check.Cardinality;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.qualityprofile.db.ActiveRuleDao;
 import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.rule.RuleDao;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.server.search.Hit;
 import org.sonar.server.tester.ServerTester;
@@ -40,19 +42,24 @@ public class RuleMediumTest {
 
   @Rule
   public ServerTester tester = new ServerTester()
-  //.setProperty("sonar.log.profilingLevel", "FULL")
-  .setProperty("sonar.es.http.port", "8888");
+    // .setProperty("sonar.log.profilingLevel", "FULL")
+    .setProperty("sonar.es.http.port", "8888");
 
   private RuleDto dto;
   private ActiveRuleDto adto;
 
   @Before
-  public void setup(){
+  public void setup() {
     dto = getRuleDto(1);
     adto = getActiveRuleDto(dto);
   }
 
-  private ActiveRuleDto getActiveRuleDto(RuleDto dto){
+  @After
+  public void teardown() {
+    tester.stop();
+  }
+
+  private ActiveRuleDto getActiveRuleDto(RuleDto dto) {
     return new ActiveRuleDto()
       .setId(1)
       .setNoteCreatedAt(new Date())
@@ -61,12 +68,12 @@ public class RuleMediumTest {
       .setProfileId(1)
       .setParentId(0)
       .setSeverity(3);
-    }
+  }
 
   private RuleDto getRuleDto(int id) {
     return new RuleDto()
-      .setId(id)
-      .setRuleKey("NewRuleKey="+id)
+      // .setId(id)
+      .setRuleKey("NewRuleKey=" + id)
       .setRepositoryKey("plugin")
       .setName("new name")
       .setDescription("new description")
@@ -97,13 +104,6 @@ public class RuleMediumTest {
     RuleIndex index = tester.get(RuleIndex.class);
 
     dao.insert(dto);
-    adao.insert(adto);
-
-    try {
-      Thread.sleep(200);
-    } catch (InterruptedException e) {
-      ;
-    }
 
     Hit hit = index.getByKey(dto.getKey());
     assertThat(hit.getFields().get("ruleKey")).isEqualTo(dto.getRuleKey());
@@ -116,10 +116,9 @@ public class RuleMediumTest {
 
     dao.insert(dto);
 
-    //org.sonar.server.rule2.Rule rule = service.getByKey(dto.getKey());
-
-    //assertThat(rule.key()).isEqualTo(dto.getKey());
+    org.sonar.server.rule2.Rule rule = service.getByKey(dto.getKey());
 
+    assertThat(rule.key()).isEqualTo(dto.getKey());
 
   }
 }