]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5237 - complete skeleton stack in rule2 package
authorStephane Gamard <stephane.gamard@searchbox.com>
Mon, 28 Apr 2014 09:39:30 +0000 (11:39 +0200)
committerStephane Gamard <stephane.gamard@searchbox.com>
Mon, 28 Apr 2014 09:39:30 +0000 (11:39 +0200)
18 files changed:
sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/cluster/WorkQueue.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/db/Dao.java
sonar-server/src/main/java/org/sonar/server/rule2/RuleConstants.java [new file with mode: 0644]
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/RuleDto.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 [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleQuery.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java [new file with mode: 0644]
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/IndexSynchronizer.java
sonar-server/src/test/java/org/sonar/server/cluster/LocalNonBlockingWorkQueueTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/es/BaseIndexTest.java [deleted file]
sonar-server/src/test/java/org/sonar/server/rule2/RuleIndexTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/search/BaseIndexTest.java [new file with mode: 0644]

diff --git a/sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java b/sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java
new file mode 100644 (file)
index 0000000..c3c5360
--- /dev/null
@@ -0,0 +1,73 @@
+package org.sonar.server.cluster;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+public class LocalNonBlockingWorkQueue implements WorkQueue{
+
+  private final static int WORKQUEUE_INITIAL_CAPACITY = 20;
+
+  private ConcurrentHashMap<String, Queue<Serializable>> index;
+  private ConcurrentHashMap<String, Queue<Serializable>> update;
+  private ConcurrentHashMap<String, Queue<Serializable>> delete;
+
+  public LocalNonBlockingWorkQueue(){
+    this.index = new ConcurrentHashMap<String, Queue<Serializable>>(WORKQUEUE_INITIAL_CAPACITY);
+    this.update = new ConcurrentHashMap<String, Queue<Serializable>>(WORKQUEUE_INITIAL_CAPACITY);
+    this.delete = new ConcurrentHashMap<String, Queue<Serializable>>(WORKQUEUE_INITIAL_CAPACITY);
+  }
+
+  private Integer enqueue(Map<String, Queue<Serializable>> map, String indexName, Serializable key){
+    if(!map.containsKey(indexName)){
+      map.put(indexName, new ConcurrentLinkedQueue<Serializable>());
+    }
+    map.get(indexName).offer(key);
+    return 0;
+  }
+
+  private Object dequeue(Map<String, Queue<Serializable>> map, String indexName){
+    return (map.containsKey(indexName))?
+      map.get(indexName).poll():
+        null;
+  }
+
+  @Override
+  public Integer enqueInsert(String indexName, Serializable key) {
+    return this.enqueue(index, indexName, key);
+  }
+
+  @Override
+  public Integer enqueUpdate(String indexName, Serializable key) {
+    return this.enqueue(update, indexName, key);
+  }
+
+  @Override
+  public Integer enqueDelete(String indexName, Serializable key) {
+    return this.enqueue(delete, indexName, key);
+  }
+
+  @Override
+  public Object dequeInsert(String indexName) {
+    return this.dequeue(index, indexName);
+  }
+
+  @Override
+  public Object dequeUpdate(String indexName) {
+    return this.dequeue(update, indexName);
+  }
+
+  @Override
+  public Object dequeDelete(String indexName) {
+    return this.dequeue(delete, indexName);
+  }
+
+  @Override
+  public Status getStatus(Integer workId) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}
index 1b6a89117c936de3d75435acec6f4dd142b98632..79c3b520dc9094c80196241123872b7862ea83e2 100644 (file)
  */
 package org.sonar.server.cluster;
 
+import java.io.Serializable;
+
 public interface WorkQueue {
 
-  Integer enqueInsert(String indexName, Object key);
+  Integer enqueInsert(String indexName, Serializable key);
 
-  Integer enqueUpdate(String indexName, Object key);
+  Integer enqueUpdate(String indexName, Serializable key);
 
-  Integer enqueDelete(String indexName, Object key);
+  Integer enqueDelete(String indexName, Serializable key);
 
   Object dequeInsert(String indexName);
 
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..21a2270
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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.persistence.MyBatis;
+import org.sonar.server.cluster.WorkQueue;
+
+import java.io.Serializable;
+
+public abstract class BaseDao<E extends Dto<K>, K extends Serializable> implements Dao<E, K> {
+
+  private MyBatis myBatis;
+  private WorkQueue workQueue;
+
+  protected BaseDao(WorkQueue workQueue, MyBatis myBatis) {
+    this.myBatis = myBatis;
+    this.workQueue = workQueue;
+  }
+
+  protected abstract String getIndexName();
+
+  protected void enqueInsert(K key) {
+    this.workQueue.enqueInsert(this.getIndexName(), key);
+  }
+
+  protected void enqueUpdate(K key) {
+    this.workQueue.enqueUpdate(this.getIndexName(), key);
+  }
+
+  protected void enqueDelete(K key) {
+    this.workQueue.enqueDelete(this.getIndexName(), key);
+  }
+
+  protected MyBatis getMyBatis(){
+    return this.myBatis;
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public E getByKey(K key) {
+    E item = null;
+    SqlSession session = getMyBatis().openSession();
+    item = (E) session.getMapper(this.getClass()).getByKey(key);
+    MyBatis.closeQuietly(session);
+    return item;
+  }
+
+  @Override
+  public E update(E item) {
+    SqlSession session = getMyBatis().openSession();
+    E result = null;
+    try {
+      result = (E) session.getMapper(this.getClass()).update(item);
+      session.commit();
+    } finally {
+      this.enqueUpdate(item.getKey());
+      MyBatis.closeQuietly(session);
+      return result;
+    }
+  }
+
+  @Override
+  public E insert(E item) {
+    SqlSession session = getMyBatis().openSession();
+    E result = null;
+    try {
+      result = (E) session.getMapper(this.getClass()).insert(item);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+      this.enqueInsert(item.getKey());
+      return result;
+    }
+  }
+
+  @Override
+  public void delete(E item) {
+    this.deleteByKey(item.getKey());
+  }
+
+  @Override
+  public void deleteByKey(K key) {
+    SqlSession session = getMyBatis().openSession();
+    try {
+      session.getMapper(this.getClass()).deleteByKey(key);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+      this.enqueDelete(key);
+    }
+  }
+}
index 44fd54dd41a63ea87e7f20154abad69ca89c443b..e3fad2e59f5efb915ce9bc4a560b20246ae96178 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.db;
 
 import java.io.Serializable;
+import java.util.Collection;
 
 public interface Dao<E extends Dto<K>, K extends Serializable> {
 
@@ -33,4 +34,6 @@ public interface Dao<E extends Dto<K>, K extends Serializable> {
 
   public void deleteByKey(K key);
 
+  public Collection<K> insertsSince(Long timestamp);
+
 }
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleConstants.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleConstants.java
new file mode 100644 (file)
index 0000000..98abd6f
--- /dev/null
@@ -0,0 +1,7 @@
+package org.sonar.server.rule2;
+
+public interface RuleConstants {
+
+  public static final String INDEX_NAME = "rules";
+  public static final String ES_TYPE = "rule";
+}
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..3bc9875
--- /dev/null
@@ -0,0 +1,26 @@
+package org.sonar.server.rule2;
+
+import java.util.Collection;
+
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.cluster.WorkQueue;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.server.db.BaseDao;
+
+public class RuleDao extends BaseDao<RuleDto, RuleKey> {
+
+  protected RuleDao(WorkQueue workQueue, MyBatis myBatis) {
+    super(workQueue, myBatis);
+  }
+
+  @Override
+  protected String getIndexName() {
+    return RuleConstants.INDEX_NAME;
+  }
+
+  @Override
+  public Collection<RuleKey> insertsSince(Long timestamp) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleDto.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleDto.java
new file mode 100644 (file)
index 0000000..621de3a
--- /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 org.sonar.api.rule.RuleKey;
+
+import org.sonar.core.rule.SeverityUtil;
+import org.sonar.server.db.Dto;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.check.Cardinality;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Date;
+
+public final class RuleDto implements Dto<RuleKey> {
+
+  public static final Integer DISABLED_CHARACTERISTIC_ID = -1;
+
+  private String repositoryKey;
+  private String ruleKey;
+  private String description;
+  private String status;
+  private String name;
+  private String configKey;
+  private Integer severity;
+  private Cardinality cardinality;
+  private String language;
+  private Integer parentId;
+  private String noteData;
+  private String noteUserLogin;
+  private Date noteCreatedAt;
+  private Date noteUpdatedAt;
+  private Integer subCharacteristicId;
+  private Integer defaultSubCharacteristicId;
+  private String remediationFunction;
+  private String defaultRemediationFunction;
+  private String remediationCoefficient;
+  private String defaultRemediationCoefficient;
+  private String remediationOffset;
+  private String defaultRemediationOffset;
+  private String effortToFixDescription;
+  private Date createdAt;
+  private Date updatedAt;
+
+  @Override
+  public RuleKey getKey() {
+    return RuleKey.of(this.getRepositoryKey(), this.getRuleKey());
+  }
+
+  public String getRepositoryKey() {
+    return repositoryKey;
+  }
+
+  public RuleDto setRepositoryKey(String repositoryKey) {
+    this.repositoryKey = repositoryKey;
+    return this;
+  }
+
+  public String getRuleKey() {
+    return ruleKey;
+  }
+
+  public RuleDto setRuleKey(String ruleKey) {
+    this.ruleKey = ruleKey;
+    return this;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public RuleDto setDescription(String description) {
+    this.description = description;
+    return this;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public RuleDto setStatus(String status) {
+    this.status = status;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public RuleDto setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public String getConfigKey() {
+    return configKey;
+  }
+
+  public RuleDto setConfigKey(String configKey) {
+    this.configKey = configKey;
+    return this;
+  }
+
+  public Integer getSeverity() {
+    return severity;
+  }
+
+  public String getSeverityString() {
+    return SeverityUtil.getSeverityFromOrdinal(severity);
+  }
+
+  public RuleDto setSeverity(String severity) {
+    this.severity = SeverityUtil.getOrdinalFromSeverity(severity);
+    return this;
+  }
+
+  public RuleDto setSeverity(Integer severity) {
+    this.severity = severity;
+    return this;
+  }
+
+
+  public Cardinality getCardinality() {
+    return cardinality;
+  }
+
+  public RuleDto setCardinality(Cardinality cardinality) {
+    this.cardinality = cardinality;
+    return this;
+  }
+
+  public String getLanguage() {
+    return language;
+  }
+
+  public RuleDto setLanguage(String language) {
+    this.language = language;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getParentId() {
+    return parentId;
+  }
+
+  public RuleDto setParentId(@Nullable Integer parentId) {
+    this.parentId = parentId;
+    return this;
+  }
+
+  public String getNoteData() {
+    return noteData;
+  }
+
+  public RuleDto setNoteData(String noteData) {
+    this.noteData = noteData;
+    return this;
+  }
+
+  public String getNoteUserLogin() {
+    return noteUserLogin;
+  }
+
+  public RuleDto setNoteUserLogin(String noteUserLogin) {
+    this.noteUserLogin = noteUserLogin;
+    return this;
+  }
+
+  public Date getNoteCreatedAt() {
+    return noteCreatedAt;
+  }
+
+  public RuleDto setNoteCreatedAt(Date noteCreatedAt) {
+    this.noteCreatedAt = noteCreatedAt;
+    return this;
+  }
+
+  public Date getNoteUpdatedAt() {
+    return noteUpdatedAt;
+  }
+
+  public RuleDto setNoteUpdatedAt(Date noteUpdatedAt) {
+    this.noteUpdatedAt = noteUpdatedAt;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getSubCharacteristicId() {
+    return subCharacteristicId;
+  }
+
+  public RuleDto setSubCharacteristicId(@Nullable Integer subCharacteristicId) {
+    this.subCharacteristicId = subCharacteristicId;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getDefaultSubCharacteristicId() {
+    return defaultSubCharacteristicId;
+  }
+
+  public RuleDto setDefaultSubCharacteristicId(@Nullable Integer defaultSubCharacteristicId) {
+    this.defaultSubCharacteristicId = defaultSubCharacteristicId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getRemediationFunction() {
+    return remediationFunction;
+  }
+
+  public RuleDto setRemediationFunction(@Nullable String remediationFunction) {
+    this.remediationFunction = remediationFunction;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDefaultRemediationFunction() {
+    return defaultRemediationFunction;
+  }
+
+  public RuleDto setDefaultRemediationFunction(@Nullable String defaultRemediationFunction) {
+    this.defaultRemediationFunction = defaultRemediationFunction;
+    return this;
+  }
+
+  @CheckForNull
+  public String getRemediationCoefficient() {
+    return remediationCoefficient;
+  }
+
+  public RuleDto setRemediationCoefficient(@Nullable String remediationCoefficient) {
+    this.remediationCoefficient = remediationCoefficient;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDefaultRemediationCoefficient() {
+    return defaultRemediationCoefficient;
+  }
+
+  public RuleDto setDefaultRemediationCoefficient(@Nullable String defaultRemediationCoefficient) {
+    this.defaultRemediationCoefficient = defaultRemediationCoefficient;
+    return this;
+  }
+
+  @CheckForNull
+  public String getRemediationOffset() {
+    return remediationOffset;
+  }
+
+  public RuleDto setRemediationOffset(@Nullable String remediationOffset) {
+    this.remediationOffset = remediationOffset;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDefaultRemediationOffset() {
+    return defaultRemediationOffset;
+  }
+
+  public RuleDto setDefaultRemediationOffset(@Nullable String defaultRemediationOffset) {
+    this.defaultRemediationOffset = defaultRemediationOffset;
+    return this;
+  }
+
+  @CheckForNull
+  public String getEffortToFixDescription() {
+    return effortToFixDescription;
+  }
+
+  public RuleDto setEffortToFixDescription(@Nullable String effortToFixDescription) {
+    this.effortToFixDescription = effortToFixDescription;
+    return this;
+  }
+
+  public Date getCreatedAt() {
+    return createdAt;
+  }
+
+  public RuleDto setCreatedAt(Date createdAt) {
+    this.createdAt = createdAt;
+    return this;
+  }
+
+  public Date getUpdatedAt() {
+    return updatedAt;
+  }
+
+  public RuleDto setUpdatedAt(Date updatedAt) {
+    this.updatedAt = updatedAt;
+    return this;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof RuleDto)) {
+      return false;
+    }
+    if (this == obj) {
+      return true;
+    }
+    RuleDto other = (RuleDto) obj;
+    return new EqualsBuilder()
+      .append(repositoryKey, other.getRepositoryKey())
+      .append(ruleKey, other.getRuleKey())
+      .isEquals();
+  }
+
+  @Override
+  public int hashCode() {
+    return new HashCodeBuilder(17, 37)
+      .append(repositoryKey)
+      .append(ruleKey)
+      .toHashCode();
+  }
+
+  @Override
+  public String toString() {
+    return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
+  }
+}
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..89ccff4
--- /dev/null
@@ -0,0 +1,97 @@
+package org.sonar.server.rule2;
+
+import org.sonar.api.rule.Severity;
+import org.sonar.api.server.debt.DebtRemediationFunction;
+
+import java.util.Date;
+import java.util.List;
+
+import org.sonar.api.rule.RuleKey;
+
+public class RuleImpl implements Rule {
+
+  @Override
+  public RuleKey key() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String language() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String name() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String description() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Severity severity() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String status() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public boolean template() {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  @Override
+  public List<String> tags() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public List<RuleParam> params() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String debtCharacteristicKey() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String debtSubCharacteristicKey() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public DebtRemediationFunction debtRemediationFunction() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Date createdAt() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Date updatedAt() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java
new file mode 100644 (file)
index 0000000..d7bda89
--- /dev/null
@@ -0,0 +1,123 @@
+package org.sonar.server.rule2;
+
+import org.elasticsearch.common.settings.ImmutableSettings;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.server.cluster.WorkQueue;
+import org.sonar.server.search.BaseIndex;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+
+
+public class RuleIndex extends BaseIndex<RuleKey> {
+
+  private static final Logger LOG = LoggerFactory.getLogger(RuleIndex.class);
+
+  public RuleIndex(WorkQueue workQueue, RuleDao dao, Profiling profiling) {
+    super(workQueue, dao, profiling);
+  }
+
+  @Override
+  public String getIndexName() {
+    return RuleConstants.INDEX_NAME;
+  }
+
+  @Override
+  protected String getType() {
+    return RuleConstants.ES_TYPE;
+  }
+
+  protected QueryBuilder getKeyQuery(RuleKey key){
+    return QueryBuilders.boolQuery()
+    .must(QueryBuilders.termQuery("repositoryKey", key.repository()))
+    .must(QueryBuilders.termQuery("ruleKey", key.rule()));
+  }
+
+  @Override
+  protected Settings getIndexSettings() {
+    try {
+      return ImmutableSettings.builder()
+        .loadFromSource(
+          jsonBuilder().startObject()
+          .startObject("index")
+            .field("number_of_replicas", 0)
+            .field("number_of_shards",4)
+            .startObject("mapper")
+              .field("dynamic", true)
+            .endObject()
+            .startObject("analysis")
+              .startObject("analyzer")
+                .startObject("path_analyzer")
+                  .field("type", "custom")
+                  .field("tokenizer", "path_hierarchy")
+                .endObject()
+              .endObject()
+            .endObject()
+          .endObject().toString())
+        .build();
+    } catch (IOException e) {
+      LOG.error("Could not create index settings for {}",this.getIndexName());
+      return ImmutableSettings.builder().build();
+    }
+  }
+
+  @Override
+  protected XContentBuilder getMapping() {
+    try {
+      return jsonBuilder().startObject()
+        .startObject("issue")
+          .startObject("properties")
+            .startObject("component.path")
+              .field("type", "string")
+              .field("index_analyzer", "path_analyzer")
+              .field("search_analyzer", "keyword")
+            .endObject()
+          .startObject("rule.name")
+            .field("type", "string")
+            .field("analyzer", "keyword")
+          .endObject()
+          .startObject("root.id")
+            .field("type", "multi_field")
+            .startObject("fields")
+              .startObject("str")
+                .field("type", "string")
+                .field("index","analyzed")
+                .field("analyzer", "default")
+              .endObject()
+              .startObject("num")
+                .field("type", "long")
+                .field("index","analyzed")
+              .endObject()
+          .endObject()
+        .endObject()
+      .endObject().endObject();
+    } catch (IOException e) {
+      LOG.error("Could not create mapping for {}",this.getIndexName());
+      return null;
+    }
+  }
+
+  @Override
+  public Map<String, Object> normalize(RuleKey key) {
+    //Use a MyBatis to normalize the Rule form multiple Table
+    return null;
+  }
+
+  @Override
+  public Collection<RuleKey> synchronizeSince(Long date) {
+    //Use MyBatis to get the RuleKey created since date X
+    return null;
+  }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleQuery.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleQuery.java
new file mode 100644 (file)
index 0000000..2a7cc34
--- /dev/null
@@ -0,0 +1,5 @@
+package org.sonar.server.rule2;
+
+public class RuleQuery {
+
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java b/sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java
new file mode 100644 (file)
index 0000000..1260fe9
--- /dev/null
@@ -0,0 +1,29 @@
+package org.sonar.server.rule2;
+
+import org.sonar.server.search.Hit;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class RuleService {
+
+  private RuleDao dao;
+  private RuleIndex index;
+
+  public RuleService(RuleDao dao, RuleIndex index){
+    this.dao = dao;
+    this.index = index;
+  }
+
+  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 new RuleImpl();
+  }
+}
index e3716781f891bacebf959e7b572c2eecbc0dae03..9eaf598196ec81d427e6382065914333246c3d1b 100644 (file)
 package org.sonar.server.search;
 
 import org.elasticsearch.action.admin.cluster.stats.ClusterStatsNodes;
+import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
+import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.action.index.IndexResponse;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.client.transport.TransportClient;
 import org.elasticsearch.common.settings.ImmutableSettings;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.transport.InetSocketTransportAddress;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.profiling.Profiling.Level;
 import org.sonar.core.profiling.StopWatch;
 import org.sonar.server.cluster.WorkQueue;
+import org.sonar.server.db.Dao;
 
 import java.io.Serializable;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
 
-public abstract class BaseIndex<K extends Serializable> implements Index<K>{
-
-  private static final String ES_EXECUTE_FAILED = "Failed execution of {}. Root is {}";
-
-  private static final String BULK_EXECUTE_FAILED = "Execution of bulk operation failed";
-  private static final String BULK_INTERRUPTED = "Interrupted during bulk operation";
+public abstract class BaseIndex<K extends Serializable> implements Index<K> {
 
   private static final String PROFILE_DOMAIN = "es";
   private static final Logger LOG = LoggerFactory.getLogger(BaseIndex.class);
@@ -55,17 +56,51 @@ public abstract class BaseIndex<K extends Serializable> implements Index<K>{
   private final Profiling profiling;
   private Client client;
   private WorkQueue workQueue;
-  private IndexSynchronizer synchronizer;
+  private IndexSynchronizer<K> synchronizer;
+  protected Dao<?,K> dao;
 
-  public BaseIndex(WorkQueue workQueue, Profiling profiling) {
+  public BaseIndex(WorkQueue workQueue, Dao<?,K> dao, Profiling profiling) {
     this.profiling = profiling;
     this.workQueue = workQueue;
     this.synchronizer = IndexSynchronizer.getOnetimeSynchronizer(this, this.workQueue);
+    this.dao = dao;
+  }
+
+  protected Dao<?,K> getDao(){
+    return this.dao;
+  }
+
+  protected Client getClient(){
+    return this.client;
   }
 
+  /* Component Methods */
+
   @Override
   public void start() {
 
+    /* Connect to the local ES Cluster */
+    this.connect();
+
+    /* Setup the index if necessary */
+    this.intializeIndex();
+
+    /* Launch synchronization */
+    synchronizer.start();
+  }
+
+  @Override
+  public void stop() {
+    if (client != null) {
+      client.close();
+    }
+  }
+
+  private StopWatch createWatch() {
+    return profiling.start(PROFILE_DOMAIN, Level.FULL);
+  }
+
+  public void connect(){
     /* Settings to access our local ES node */
     Settings settings = ImmutableSettings.settingsBuilder()
       .put("client.transport.sniff", true)
@@ -76,30 +111,35 @@ public abstract class BaseIndex<K extends Serializable> implements Index<K>{
     this.client = new TransportClient(settings)
       .addTransportAddress(new InetSocketTransportAddress(LOCAL_ES_NODE_HOST, LOCAL_ES_NODE_PORT));
 
-    /* Cannot do that yet, need version >= 1.0
-    ImmutableList<DiscoveryNode> nodes = client.connectedNodes();
-    if (nodes.isEmpty()) {
-        throw new ElasticSearchUnavailableException("No nodes available. Verify ES is running!");
-    } else {
-        log.info("connected to nodes: " + nodes.toString());
-    }
-    */
-
-    /* Launch synchronization */
-    synchronizer.start();
+    /*
+     * Cannot do that yet, need version >= 1.0
+     * ImmutableList<DiscoveryNode> nodes = client.connectedNodes();
+     * if (nodes.isEmpty()) {
+     * throw new ElasticSearchUnavailableException("No nodes available. Verify ES is running!");
+     * } else {
+     * log.info("connected to nodes: " + nodes.toString());
+     * }
+     */
   }
 
-  @Override
-  public void stop() {
-    if (client != null) {
-      client.close();
+  /* Cluster And ES Stats/Client methods */
+
+  private void intializeIndex() {
+
+    String index = this.getIndexName();
+
+    IndicesExistsResponse indexExistsResponse = client.admin().indices()
+      .prepareExists(index).execute().actionGet();
+
+    if (!indexExistsResponse.isExists()) {
+
+      client.admin().indices().prepareCreate(index)
+        .setSettings(getIndexSettings())
+        .addMapping(getType(), getMapping())
+        .execute().actionGet();
     }
   }
 
-  public Collection<K> synchronizeSince(Long date) {
-    // TODO Auto-generated method stub
-    return Collections.EMPTY_LIST;
-  }
 
   public ClusterStatsNodes getNodesStats() {
     StopWatch watch = createWatch();
@@ -110,71 +150,87 @@ public abstract class BaseIndex<K extends Serializable> implements Index<K>{
     }
   }
 
-  private StopWatch createWatch() {
-    return profiling.start(PROFILE_DOMAIN, Level.FULL);
-  }
+
+  /* Index management and Tx methods */
+
+  protected abstract Settings getIndexSettings();
+
+  protected abstract String getType();
+
+  protected abstract XContentBuilder getMapping();
+
+  public abstract Collection<K> synchronizeSince(Long date);
+
+
+  /* Base CRUD methods */
+
+  protected abstract QueryBuilder getKeyQuery(K key);
 
   @Override
   public Hit getByKey(K key) {
-    // TODO Auto-generated method stub
+    getClient().prepareSearch(this.getIndexName())
+      .setQuery(getKeyQuery(key))
+      .get();
     return null;
   }
 
   @Override
   public void insert(K key) {
-    // TODO Auto-generated method stub
-
+    this.update(key);
   }
 
   @Override
-  public void udpate(K key) {
-    // TODO Auto-generated method stub
+  public void update(K key) {
+    IndexResponse result = getClient().index(new IndexRequest()
+      .type(this.getType())
+      .index(this.getIndexName())
+      .source(this.normalize(key))).actionGet();
 
   }
 
   @Override
   public void delete(K key) {
-    // TODO Auto-generated method stub
-
+    DeleteByQueryResponse result = getClient().prepareDeleteByQuery(this.getIndexName())
+      .setQuery(getKeyQuery(key)).get();
   }
 
-  @Override
-  public K dequeueInsert() {
-    // TODO Auto-generated method stub
-    return null;
-  }
+  /* Synchronization methods */
 
-  @Override
-  public K dequeueUpdate() {
-    // TODO Auto-generated method stub
-    return null;
-  }
+  Long lastSynch = 0l;
+  long cooldown = 30000;
 
   @Override
-  public K dequeueDelete() {
-    // TODO Auto-generated method stub
-    return null;
+  public void setLastSynchronization(Long time) {
+    if(time > (getLastSynchronization() + cooldown)){
+      LOG.trace("Updating synchTime updating");
+      lastSynch = time;
+    } else {
+      LOG.trace("Not updating synchTime, still cooling down");
+    }
+
   }
 
   @Override
-  public abstract Map<String, Object> normalize(K key);
-
+  public Long getLastSynchronization() {
+    // need to read that in the admin index;
+    return 0l;
+  }
 
   @Override
-  public String getIndexName() {
-    // TODO Auto-generated method stub
-    return null;
+  @SuppressWarnings("unchecked")
+  public K dequeueInsert() {
+    return (K) this.workQueue.dequeUpdate(this.getIndexName());
   }
 
   @Override
-  public void setLastSynchronization(Long time) {
-    // TODO Auto-generated method stub
-
+  @SuppressWarnings("unchecked")
+  public K dequeueUpdate() {
+    return (K) this.workQueue.dequeUpdate(this.getIndexName());
   }
 
   @Override
-  public Long getLastSynchronization() {
-    // TODO Auto-generated method stub
-    return null;
+  @SuppressWarnings("unchecked")
+  public K dequeueDelete() {
+    return (K) this.workQueue.dequeDelete(this.getIndexName());
   }
 }
index 4505806039cdf7ad2d854b553e0bce58e8c13c6c..25c91080bc127a254113072dd80f0d39b67c9e03 100644 (file)
@@ -34,7 +34,7 @@ public interface Index<K extends Serializable> extends Startable {
 
   void insert(K key);
 
-  void udpate(K key);
+  void update(K key);
 
   void delete(K key);
 
index a7a19d08577c07461dc968f460a9a1573bdcd3d9..0547675b535c37205797c72542dcdec7f2d135ab 100644 (file)
@@ -23,9 +23,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.server.cluster.WorkQueue;
 
-import java.util.Date;
+import java.io.Serializable;
 
-public class IndexSynchronizer {
+public class IndexSynchronizer<K extends Serializable> {
 
   private static final Logger LOG = LoggerFactory.getLogger(IndexSynchronizer.class);
 
@@ -34,49 +34,49 @@ public class IndexSynchronizer {
   private long wait = 0;
   private boolean continuous;
 
-  private final Index<?> index;
+  private final Index<K> index;
   private final WorkQueue workQueue;
 
-  public static IndexSynchronizer getContinuousSynchronizer(Index<?> index, WorkQueue workQueue) {
-    return new IndexSynchronizer(index, workQueue)
+  public static <K extends Serializable> IndexSynchronizer<K> getContinuousSynchronizer(Index<K> index, WorkQueue workQueue) {
+    return new IndexSynchronizer<K>(index, workQueue)
       .setContinuous(true)
       .setWait(DEFAULT_WAIT_TIME);
   }
 
-  public static IndexSynchronizer getContinuousSynchronizer(Index<?> index, WorkQueue workQueue, Long wait) {
-    return new IndexSynchronizer(index, workQueue)
+  public static <K extends Serializable> IndexSynchronizer<K> getContinuousSynchronizer(Index<K> index, WorkQueue workQueue, Long wait) {
+    return new IndexSynchronizer<K>(index, workQueue)
       .setContinuous(true)
       .setWait(wait);
   }
 
-  public static IndexSynchronizer getOnetimeSynchronizer(Index<?> index, WorkQueue workQueue) {
-    return new IndexSynchronizer(index, workQueue)
+  public static <K extends Serializable> IndexSynchronizer<K> getOnetimeSynchronizer(Index<K> index, WorkQueue workQueue) {
+    return new IndexSynchronizer<K>(index, workQueue)
       .setContinuous(false);
   }
 
-  private IndexSynchronizer(Index<?> index, WorkQueue workQueue) {
+  private IndexSynchronizer(Index<K> index, WorkQueue workQueue) {
     this.index = index;
     this.workQueue = workQueue;
   }
 
-  private IndexSynchronizer setWait(Long wait) {
+  private IndexSynchronizer<K> setWait(Long wait) {
     this.wait = wait;
     return this;
   }
 
-  private IndexSynchronizer setContinuous(Boolean continuous) {
+  private IndexSynchronizer<K> setContinuous(Boolean continuous) {
     this.continuous = continuous;
     return this;
   }
 
-  public IndexSynchronizer start() {
+  public IndexSynchronizer<K> start() {
 
     LOG.info("Starting synchronization thread for ", index.getClass().getSimpleName());
 
     Long since = index.getLastSynchronization();
     index.setLastSynchronization(System.currentTimeMillis());
 
-    for (Object key : index.synchronizeSince(since)) {
+    for (K key : index.synchronizeSince(since)) {
       if (LOG.isTraceEnabled()) {
         LOG.trace("Adding {} to workQueue for {}", key, index.getClass().getSimpleName());
       }
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
new file mode 100644 (file)
index 0000000..117db38
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.junit.Test;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+
+public class LocalNonBlockingWorkQueueTest {
+
+  private static final String WORKING_INDEX = "working_index";
+  private static final String NON_WORKING_INDEX = "non_working_index";
+
+  @Test
+  public void test_insert_queue(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    assertThat(queue.dequeInsert(WORKING_INDEX)).isNull();
+    assertThat(queue.dequeInsert(NON_WORKING_INDEX)).isNull();
+
+    queue.enqueInsert(WORKING_INDEX, new Integer(0));
+    assertThat(queue.dequeInsert(NON_WORKING_INDEX)).isNull();
+
+    Object dequeued = queue.dequeInsert(WORKING_INDEX);
+    assertThat(queue.dequeInsert(NON_WORKING_INDEX)).isNull();
+    assertThat(queue.dequeInsert(WORKING_INDEX)).isNull();
+
+    assertThat(dequeued).isEqualTo(new Integer(0));
+  }
+
+  @Test
+  public void test_update_queue(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    assertThat(queue.dequeUpdate(WORKING_INDEX)).isNull();
+    assertThat(queue.dequeUpdate(NON_WORKING_INDEX)).isNull();
+
+    queue.enqueUpdate(WORKING_INDEX, new Integer(0));
+    assertThat(queue.dequeUpdate(NON_WORKING_INDEX)).isNull();
+
+    Object dequeued = queue.dequeUpdate(WORKING_INDEX);
+    assertThat(queue.dequeUpdate(NON_WORKING_INDEX)).isNull();
+    assertThat(queue.dequeUpdate(WORKING_INDEX)).isNull();
+
+    assertThat(dequeued).isEqualTo(new Integer(0));
+  }
+
+  @Test
+  public void test_delete_queue(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    assertThat(queue.dequeDelete(WORKING_INDEX)).isNull();
+    assertThat(queue.dequeDelete(NON_WORKING_INDEX)).isNull();
+
+    queue.enqueDelete(WORKING_INDEX, new Integer(0));
+    assertThat(queue.dequeDelete(NON_WORKING_INDEX)).isNull();
+
+    Object dequeued = queue.dequeDelete(WORKING_INDEX);
+    assertThat(queue.dequeDelete(NON_WORKING_INDEX)).isNull();
+    assertThat(queue.dequeDelete(WORKING_INDEX)).isNull();
+
+    assertThat(dequeued).isEqualTo(new Integer(0));
+  }
+
+  @Test
+  public void test_enque_seralizable_object(){
+
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    class NonSerializable implements Serializable{
+      private Object var1;
+      private Map<String, Object> objs;
+    }
+
+    NonSerializable nonSer = new NonSerializable();
+    assertThat(queue.enqueInsert(WORKING_INDEX, nonSer)).isNotNull();
+
+    Object dequeued = queue.dequeInsert(WORKING_INDEX);
+    assertThat(queue.dequeInsert(NON_WORKING_INDEX)).isNull();
+
+    assertThat(dequeued).isNotNull();
+    assertThat(dequeued.getClass()).isEqualTo(NonSerializable.class);
+  }
+
+  @Test
+  public void test_under_queue_capacity(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    for(int i = 0; i < 10; i++){
+      assertThat(queue.enqueDelete(WORKING_INDEX, i)).isNotNull();
+    }
+
+    for(int i = 0; i < 10; i++){
+      assertThat(queue.dequeDelete(WORKING_INDEX)).isNotNull();
+    }
+    assertThat(queue.dequeDelete(WORKING_INDEX)).isNull();
+
+  }
+
+  @Test
+  public void test_over_queue_capacity(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+
+    for(int i = 0; i < 100; i++){
+      assertThat(queue.enqueDelete(WORKING_INDEX, i)).isNotNull();
+    }
+
+    for(int i = 0; i < 100; i++){
+      assertThat(queue.dequeDelete(WORKING_INDEX)).isNotNull();
+    }
+    assertThat(queue.dequeDelete(WORKING_INDEX)).isNull();
+
+  }
+
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/es/BaseIndexTest.java b/sonar-server/src/test/java/org/sonar/server/es/BaseIndexTest.java
deleted file mode 100644 (file)
index 900efa8..0000000
+++ /dev/null
@@ -1,101 +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.es;
-
-import java.io.Serializable;
-import java.util.Map;
-
-import org.elasticsearch.client.transport.NoNodeAvailableException;
-import org.elasticsearch.common.settings.ImmutableSettings;
-import org.elasticsearch.node.Node;
-import org.elasticsearch.node.NodeBuilder;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.sonar.api.config.Settings;
-import org.sonar.core.profiling.Profiling;
-import org.sonar.server.search.BaseIndex;
-import static org.fest.assertions.Assertions.assertThat;
-
-@Ignore
-public class BaseIndexTest {
-
-  private static final String TEST_NODE_NAME = "es_node_for_tests";
-
-  private BaseIndex<?> searchIndex;
-  private Node node;
-
-  @Before
-  public void setUp() throws Exception {
-
-    this.node = NodeBuilder.nodeBuilder()
-      .settings(ImmutableSettings.settingsBuilder()
-        .put("node.name", TEST_NODE_NAME).build())
-      .clusterName(BaseIndex.ES_CLUSTER_NAME).node();
-  }
-
-  private BaseIndex<?> getBaseIndex(){
-    Settings settings = new Settings();
-    settings.setProperty("sonar.log.profilingLevel", "BASIC");
-    return new BaseIndex<Serializable>(null, new Profiling(settings)) {
-      @Override
-      public Map<String, Object> normalize(Serializable key) {
-        // TODO Auto-generated method stub
-        return null;
-      }
-    };
-  }
-
-  @After
-  public void tearDown() {
-    if (node != null && !node.isClosed()) {
-      node.close();
-    }
-  }
-
-  @Test
-  public void should_start_and_stop_properly() {
-
-    searchIndex = getBaseIndex();
-    searchIndex.start();
-
-    assertThat(node.client().admin().cluster().prepareClusterStats().get().getNodesStats().getCounts().getTotal())
-      .isEqualTo(searchIndex.getNodesStats().getCounts().getTotal());
-
-    searchIndex.stop();
-
-  }
-
-  @Test(expected = NoNodeAvailableException.class)
-  public void fails_when_es_gone(){
-    searchIndex = getBaseIndex();
-    searchIndex.start();
-
-    node.stop();
-
-
-    assertThat(searchIndex.getNodesStats().getCounts().getTotal());
-
-    node.start();
-
-
-  }
-}
diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/RuleIndexTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/RuleIndexTest.java
new file mode 100644 (file)
index 0000000..a1e21f9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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.server.cluster.LocalNonBlockingWorkQueue;
+
+import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchNode;
+import com.github.tlrx.elasticsearch.test.support.junit.runners.ElasticsearchRunner;
+import org.elasticsearch.node.Node;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.api.config.Settings;
+import org.sonar.core.profiling.Profiling;
+import org.sonar.server.search.BaseIndex;
+import static org.fest.assertions.Assertions.assertThat;
+
+@RunWith(ElasticsearchRunner.class)
+public class RuleIndexTest {
+
+  private static final String TEST_NODE_NAME = "es_node_for_tests";
+
+  @ElasticsearchNode(name = TEST_NODE_NAME,
+      clusterName = BaseIndex.ES_CLUSTER_NAME,
+      local = false, data = true)
+  private Node node;
+
+  @Before
+  public void setUp() throws Exception {
+
+  }
+
+  private RuleIndex getRuleIndex(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+    Settings settings = new Settings();
+    settings.setProperty("sonar.log.profilingLevel", "BASIC");
+    RuleIndex rindex =  new RuleIndex(queue, null, new Profiling(settings));
+    return rindex;
+  }
+
+  @After
+  public void tearDown() {
+    if (node != null && !node.isClosed()) {
+      node.close();
+    }
+  }
+
+  @Test
+  public void test_ruleIndex_conencts_to_es() {
+
+    RuleIndex ruleIndex = getRuleIndex();
+    ruleIndex.connect();
+
+    assertThat(node.client().admin().cluster().prepareClusterStats().get().getNodesStats().getCounts().getTotal())
+      .isEqualTo(ruleIndex.getNodesStats().getCounts().getTotal());
+
+    ruleIndex.stop();
+
+  }
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/search/BaseIndexTest.java b/sonar-server/src/test/java/org/sonar/server/search/BaseIndexTest.java
new file mode 100644 (file)
index 0000000..0f75176
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.server.cluster.LocalNonBlockingWorkQueue;
+
+import com.github.tlrx.elasticsearch.test.annotations.ElasticsearchNode;
+import com.github.tlrx.elasticsearch.test.support.junit.runners.ElasticsearchRunner;
+import org.elasticsearch.client.transport.NoNodeAvailableException;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.node.Node;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.api.config.Settings;
+import org.sonar.core.profiling.Profiling;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+@RunWith(ElasticsearchRunner.class)
+public class BaseIndexTest {
+
+  private static final String TEST_NODE_NAME = "es_node_for_tests";
+
+  @ElasticsearchNode(name = TEST_NODE_NAME,
+    clusterName = BaseIndex.ES_CLUSTER_NAME,
+    local = false, data = true)
+  private Node node;
+
+  @Before
+  public void setUp() throws Exception {
+
+  }
+
+  private BaseIndex<?> getBaseIndex(){
+    LocalNonBlockingWorkQueue queue = new LocalNonBlockingWorkQueue();
+    Settings settings = new Settings();
+    settings.setProperty("sonar.log.profilingLevel", "BASIC");
+    return new BaseIndex<Serializable>(queue, null, new Profiling(settings)) {
+
+      @Override
+      public String getIndexName() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      protected org.elasticsearch.common.settings.Settings getIndexSettings() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      protected String getType() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      protected XContentBuilder getMapping() {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Collection<Serializable> synchronizeSince(Long date) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      protected QueryBuilder getKeyQuery(Serializable key) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+
+      @Override
+      public Map<String, Object> normalize(Serializable key) {
+        // TODO Auto-generated method stub
+        return null;
+      }
+    };
+  }
+
+  @After
+  public void tearDown() {
+    if (node != null && !node.isClosed()) {
+      node.close();
+    }
+  }
+
+  @Test
+  public void baseIndex_connects_to_es() {
+    BaseIndex<?> searchIndex = getBaseIndex();
+    searchIndex.connect();
+    assertThat(node.client().admin().cluster().prepareClusterStats().get().getNodesStats().getCounts().getTotal())
+      .isEqualTo(searchIndex.getNodesStats().getCounts().getTotal());
+
+    searchIndex.stop();
+  }
+
+  @Test(expected = NoNodeAvailableException.class)
+  public void baseIndex_fails_when_es_gone(){
+    BaseIndex<?> searchIndex = getBaseIndex();
+    searchIndex.connect();
+    node.close();
+    assertThat(searchIndex.getNodesStats().getCounts().getTotal()).isNotNull();
+  }
+}