From: Stephane Gamard Date: Wed, 30 Apr 2014 05:45:12 +0000 (+0200) Subject: SONAR-5237 - Moved Dao Back to server and Using ThreadPool for QueueWorker X-Git-Tag: 4.4-RC1~1328 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=26cad71c1190b262971a42565ed97e677fe895f9;p=sonarqube.git SONAR-5237 - Moved Dao Back to server and Using ThreadPool for QueueWorker --- 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 index 00000000000..c40526345fb --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/cluster/ClusterAction.java @@ -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 index 7ed3c0dac52..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/cluster/IndexAction.java +++ /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 { - - 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; - } -} diff --git a/sonar-core/src/main/java/org/sonar/core/cluster/NullQueue.java b/sonar-core/src/main/java/org/sonar/core/cluster/NullQueue.java index d18ed3e690c..54df2784faa 100644 --- a/sonar-core/src/main/java/org/sonar/core/cluster/NullQueue.java +++ b/sonar-core/src/main/java/org/sonar/core/cluster/NullQueue.java @@ -19,23 +19,17 @@ */ 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> actions) { - - } + public void enqueue(Iterable actions) { - @CheckForNull - @Override - public IndexAction dequeue() { - return null; } } diff --git a/sonar-core/src/main/java/org/sonar/core/cluster/WorkQueue.java b/sonar-core/src/main/java/org/sonar/core/cluster/WorkQueue.java index 9c5ffcfbe02..cee9c63265e 100644 --- a/sonar-core/src/main/java/org/sonar/core/cluster/WorkQueue.java +++ b/sonar-core/src/main/java/org/sonar/core/cluster/WorkQueue.java @@ -19,15 +19,20 @@ */ 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> actions); + void enqueue(Iterable 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 index bdc6143a21d..00000000000 --- a/sonar-core/src/main/java/org/sonar/core/db/BaseDao.java +++ /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, K extends Serializable> - implements Dao { - - 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); - } - } -} diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DbSession.java b/sonar-core/src/main/java/org/sonar/core/persistence/DbSession.java index ea729a2f666..7653f694696 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DbSession.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DbSession.java @@ -19,23 +19,27 @@ */ 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> actions; + private static final Logger LOG = LoggerFactory.getLogger(DbSession.class); + + private List 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>(); + this.actions = new ArrayList(); } - 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(); } /** diff --git a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java index d25a0110065..3b5677fc9b9 100644 --- a/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java +++ b/sonar-core/src/main/java/org/sonar/core/rule/RuleDao.java @@ -20,68 +20,29 @@ 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 - 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 selectAll() { - SqlSession session = mybatis.openSession(false); + SqlSession session = mybatis.openSession(); try { return selectAll(session); } finally { @@ -94,7 +55,7 @@ public class RuleDao extends BaseDao } public List selectEnablesAndNonManual() { - SqlSession session = mybatis.openSession(false); + SqlSession session = mybatis.openSession(); try { return selectEnablesAndNonManual(session); } finally { @@ -111,7 +72,7 @@ public class RuleDao extends BaseDao } public List 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 @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 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 @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 } } + 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 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 } } - // ****************************** + //****************************** // Methods for Rule Parameters - // ****************************** + //****************************** public List selectParameters() { - SqlSession session = mybatis.openSession(false); + SqlSession session = mybatis.openSession(); try { return selectParameters(session); } finally { @@ -197,7 +185,7 @@ public class RuleDao extends BaseDao } public List 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 } public List selectParametersByRuleIds(List 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 } 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 } 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 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 } public List 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 } public List selectTagsByRuleIds(List 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 } return dtos; } - - @Override - public Collection keysOfRowsUpdatedAfter(long timestamp) { - SqlSession session = mybatis.openSession(false); - try { - final List keys = Lists.newArrayList(); - session.select("selectKeysOfRulesUpdatedSince", new Timestamp(timestamp), new ResultHandler() { - @Override - public void handleResult(ResultContext context) { - Map map = (Map) context.getResultObject(); - keys.add(RuleKey.of(map.get("repo"), map.get("rule"))); - } - }); - return keys; - } finally { - MyBatis.closeQuietly(session); - } - } } diff --git a/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java b/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java index 3e3bc22abb5..6386962c054 100644 --- a/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java +++ b/sonar-core/src/test/java/org/sonar/core/rule/RuleDaoTest.java @@ -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 keys = dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-05-17").getTime()); - assertThat(keys).hasSize(1); - assertThat(Iterables.getFirst(keys, null).rule()).isEqualTo("R2"); - } - private List idsFromRuleDtos(List ruleDtos){ return newArrayList(Iterables.transform(ruleDtos, new Function() { @Override 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 index 0a6b282f7ec..dc2e29f2247 100644 --- a/sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java +++ b/sonar-server/src/main/java/org/sonar/server/cluster/LocalNonBlockingWorkQueue.java @@ -19,32 +19,33 @@ */ 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 + implements ServerComponent, WorkQueue{ - private final ConcurrentLinkedQueue> actions = new ConcurrentLinkedQueue>(); - - @Override - public void enqueue(IndexAction indexAction) { - actions.offer(indexAction); + public LocalNonBlockingWorkQueue(){ + super(); } @Override - public void enqueue(Iterable> 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 actions) { + for (ClusterAction action : actions) { + enqueue(action); + } } } diff --git a/sonar-server/src/main/java/org/sonar/server/cluster/LocalQueueWorker.java b/sonar-server/src/main/java/org/sonar/server/cluster/LocalQueueWorker.java index 57884afc6ce..1cbc2a9b440 100644 --- a/sonar-server/src/main/java/org/sonar/server/cluster/LocalQueueWorker.java +++ b/sonar-server/src/main/java/org/sonar/server/cluster/LocalQueueWorker.java @@ -19,70 +19,56 @@ */ 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> 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>(); + 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>(); - 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 index 00000000000..fd588c97f2e --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/db/BaseDao.java @@ -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, K extends Serializable> + implements Dao { + + 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); + } + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index b2fcfe87dcd..4b3521cac18 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -19,6 +19,10 @@ */ 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 index 00000000000..87be472f55a --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/rule2/RuleDao.java @@ -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 + 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 selectAll() { + SqlSession session = mybatis.openSession(false); + try { + return selectAll(session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectAll(SqlSession session) { + return getMapper(session).selectAll(); + } + + public List selectEnablesAndNonManual() { + SqlSession session = mybatis.openSession(false); + try { + return selectEnablesAndNonManual(session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectEnablesAndNonManual(SqlSession session) { + return getMapper(session).selectEnablesAndNonManual(); + } + + public List selectNonManual(SqlSession session) { + return getMapper(session).selectNonManual(); + } + + public List 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 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 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 selectParameters() { + SqlSession session = mybatis.openSession(false); + try { + return selectParameters(session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectParameters(SqlSession session) { + return getMapper(session).selectAllParams(); + } + + public List selectParametersByRuleId(Integer ruleId) { + SqlSession session = mybatis.openSession(false); + try { + return selectParametersByRuleId(ruleId, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectParametersByRuleId(Integer ruleId, SqlSession session) { + return selectParametersByRuleIds(newArrayList(ruleId)); + } + + public List selectParametersByRuleIds(List ruleIds) { + SqlSession session = mybatis.openSession(false); + try { + return selectParametersByRuleIds(ruleIds, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectParametersByRuleIds(List ruleIds, SqlSession session) { + List dtos = newArrayList(); + List> partitionList = Lists.partition(newArrayList(ruleIds), 1000); + for (List 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 selectTags(SqlSession session) { + return getMapper(session).selectAllTags(); + } + + public List selectTagsByRuleId(Integer ruleId) { + SqlSession session = mybatis.openSession(false); + try { + return selectTagsByRuleIds(ruleId, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectTagsByRuleIds(Integer ruleId, SqlSession session) { + return selectTagsByRuleIds(newArrayList(ruleId), session); + } + + public List selectTagsByRuleIds(List ruleIds) { + SqlSession session = mybatis.openSession(false); + try { + return selectTagsByRuleIds(ruleIds, session); + } finally { + MyBatis.closeQuietly(session); + } + } + + public List selectTagsByRuleIds(List ruleIds, SqlSession session) { + List dtos = newArrayList(); + List> partitionList = Lists.partition(newArrayList(ruleIds), 1000); + for (List partition : partitionList) { + dtos.addAll(getMapper(session).selectTagsByRuleIds(partition)); + } + return dtos; + } + + @Override + public Collection keysOfRowsUpdatedAfter(long timestamp) { + SqlSession session = mybatis.openSession(false); + try { + final List keys = Lists.newArrayList(); + session.select("selectKeysOfRulesUpdatedSince", new Timestamp(timestamp), new ResultHandler() { + @Override + public void handleResult(ResultContext context) { + Map 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 index 00000000000..c3633d38c55 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/rule2/RuleImpl.java @@ -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 fields; + + public RuleImpl(){ + this.fields = new HashMap(); + } + + private RuleImpl(Map 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 tags() { + return (List) this.fields.get("tags"); + } + + @Override + public List 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()); + } + +} 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 index 6d6fd7e0036..229d65bc2b0 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/rule2/RuleIndex.java @@ -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 { 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 { 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 { 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 { } 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 {}", 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 index c712d96d2a5..ad8853d6599 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java +++ b/sonar-server/src/main/java/org/sonar/server/rule2/RuleService.java @@ -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 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); + } } diff --git a/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java b/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java index 727246c4689..e7916ca6402 100644 --- a/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java +++ b/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java @@ -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> implem private final Profiling profiling; private Client client; private final ESNode node; - private WorkQueue workQueue; private IndexSynchronizer synchronizer; protected Dao dao; public BaseIndex(WorkQueue workQueue, Dao dao, Profiling profiling, ESNode node) { this.profiling = profiling; - this.workQueue = workQueue; - this.synchronizer = new IndexSynchronizer(this, dao, this.workQueue); + this.synchronizer = new IndexSynchronizer(this, dao, workQueue); this.dao = dao; this.node = node; } @@ -167,8 +165,7 @@ public abstract class BaseIndex> implem /* Index Action Methods */ @Override - public void executeAction(IndexAction action) { - StopWatch watch = this.createWatch(); + public boolean executeAction(IndexAction action) { long start = System.currentTimeMillis(); if (action.getMethod().equals(Method.DELETE)) { this.delete(action.getKey()); @@ -177,9 +174,9 @@ public abstract class BaseIndex> 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> 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) diff --git a/sonar-server/src/main/java/org/sonar/server/search/Index.java b/sonar-server/src/main/java/org/sonar/server/search/Index.java index 6a45b550dde..d0046510e79 100644 --- a/sonar-server/src/main/java/org/sonar/server/search/Index.java +++ b/sonar-server/src/main/java/org/sonar/server/search/Index.java @@ -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 extends Startable { String getIndexName(); - void executeAction(IndexAction action); + boolean executeAction(IndexAction 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 index 00000000000..c882941fe65 --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/search/IndexAction.java @@ -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 extends ClusterAction { + + public enum Method { + INSERT, UPDATE, DELETE + } + + private String indexName; + private K key; + private Method method; + private Index 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) index; + } + + @Override + public String toString(){ + return "{IndexAction {key: " + getKey()+"}"; + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java b/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java index 0371e5309ad..56ae2f4b8e9 100644 --- a/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java +++ b/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java @@ -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 { 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(index.getIndexName(), IndexAction.Method.INSERT, key)); } return this; diff --git a/sonar-server/src/main/java/org/sonar/server/search/IndexUtils.java b/sonar-server/src/main/java/org/sonar/server/search/IndexUtils.java index 39a65b0c0a4..6680efacd84 100644 --- a/sonar-server/src/main/java/org/sonar/server/search/IndexUtils.java +++ b/sonar-server/src/main/java/org/sonar/server/search/IndexUtils.java @@ -20,16 +20,13 @@ 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 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 index 74b2b9fddf2..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/cluster/LocalNonBlockingWorkQueueTest.java +++ /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(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 index abe89bbd1bd..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/cluster/LocalQueueWorkerTest.java +++ /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 index 00000000000..704b3c6d082 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/rule2/RuleDaoTest.java @@ -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 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 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 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 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 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 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 keys = dao.keysOfRowsUpdatedAfter(DateUtils.parseDate("2014-05-17").getTime()); + assertThat(keys).hasSize(1); + assertThat(Iterables.getFirst(keys, null).rule()).isEqualTo("R2"); + } + + private List idsFromRuleDtos(List ruleDtos){ + return newArrayList(Iterables.transform(ruleDtos, new Function() { + @Override + public Integer apply(RuleDto input) { + return input.getId(); + } + })); + } +} diff --git a/sonar-server/src/test/java/org/sonar/server/rule2/RuleMediumTest.java b/sonar-server/src/test/java/org/sonar/server/rule2/RuleMediumTest.java index de48aaa6022..819bbb68177 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule2/RuleMediumTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule2/RuleMediumTest.java @@ -19,15 +19,17 @@ */ 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()); } }