*/
package org.sonar.persistence;
-import java.util.Arrays;
-import java.util.List;
-
import org.sonar.persistence.dashboard.ActiveDashboardDao;
import org.sonar.persistence.dashboard.DashboardDao;
import org.sonar.persistence.duplication.DuplicationDao;
+import org.sonar.persistence.resource.ResourceIndexDao;
import org.sonar.persistence.review.ReviewDao;
import org.sonar.persistence.rule.RuleDao;
import org.sonar.persistence.template.LoadedTemplateDao;
+import java.util.Arrays;
+import java.util.List;
+
public final class DaoUtils {
private DaoUtils() {
}
public static List<Class<?>> getDaoClasses() {
- return Arrays.<Class<?>> asList(RuleDao.class, DuplicationDao.class, ReviewDao.class, ActiveDashboardDao.class, DashboardDao.class,
- LoadedTemplateDao.class);
+ return Arrays.asList(
+ ActiveDashboardDao.class,
+ DashboardDao.class,
+ DuplicationDao.class,
+ LoadedTemplateDao.class,
+ ResourceIndexDao.class,
+ ReviewDao.class,
+ RuleDao.class);
}
}
import org.sonar.persistence.dashboard.*;
import org.sonar.persistence.duplication.DuplicationMapper;
import org.sonar.persistence.duplication.DuplicationUnitDto;
+import org.sonar.persistence.resource.ResourceDto;
import org.sonar.persistence.resource.ResourceIndexDto;
import org.sonar.persistence.resource.ResourceIndexMapper;
import org.sonar.persistence.review.ReviewDto;
loadAlias(conf, "DuplicationUnit", DuplicationUnitDto.class);
loadAlias(conf, "LoadedTemplate", LoadedTemplateDto.class);
loadAlias(conf, "Review", ReviewDto.class);
+ loadAlias(conf, "Resource", ResourceDto.class);
loadAlias(conf, "ResourceIndex", ResourceIndexDto.class);
loadAlias(conf, "Rule", RuleDto.class);
loadAlias(conf, "Widget", WidgetDto.class);
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.persistence.resource;
+
+public final class ResourceDto {
+
+ private Integer id;
+ private String name;
+ private String longName;
+ private Integer rootId;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public ResourceDto setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public ResourceDto setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Integer getRootId() {
+ return rootId;
+ }
+
+ public ResourceDto setRootId(Integer rootId) {
+ this.rootId = rootId;
+ return this;
+ }
+
+ public String getLongName() {
+ return longName;
+ }
+
+ public ResourceDto setLongName(String longName) {
+ this.longName = longName;
+ return this;
+ }
+}
*/
package org.sonar.persistence.resource;
+import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.ResultContext;
+import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.utils.TimeProfiler;
import org.sonar.persistence.MyBatis;
import java.util.Collections;
this.mybatis = mybatis;
}
- public List<ResourceIndexDto> search(String input) {
- if (StringUtils.isBlank(input) || input.length() < MINIMUM_SEARCH_SIZE) {
+ public List<ResourceIndexDto> search(String keyword) {
+ if (StringUtils.isBlank(keyword) || keyword.length() < MINIMUM_SEARCH_SIZE) {
return Collections.emptyList();
}
SqlSession sqlSession = mybatis.openSession();
try {
ResourceIndexMapper mapper = sqlSession.getMapper(ResourceIndexMapper.class);
- return mapper.selectLikeKey(normalize(input) + "%");
+ return mapper.selectByKeyword(normalize(keyword) + "%");
} finally {
sqlSession.close();
}
}
- public void index(String resourceName, int resourceId, int projectId) {
- if (StringUtils.isBlank(resourceName)) {
+ void index(ResourceDto resource, SqlSession session) {
+ String name = resource.getName();
+ if (StringUtils.isBlank(name)) {
return;
}
- String normalizedName = normalize(resourceName);
+ String normalizedName = normalize(name);
if (normalizedName.length() >= MINIMUM_KEY_SIZE) {
- SqlSession sqlSession = mybatis.openSession(ExecutorType.BATCH);
- try {
- ResourceIndexMapper mapper = sqlSession.getMapper(ResourceIndexMapper.class);
- ResourceIndexDto dto = new ResourceIndexDto().setResourceId(resourceId).setProjectId(projectId);
-
- for (int position = 0; position <= normalizedName.length() - MINIMUM_KEY_SIZE; position++) {
- dto.setPosition(position);
- dto.setKey(StringUtils.substring(normalizedName, position));
- mapper.insert(dto);
+ ResourceIndexMapper mapper = session.getMapper(ResourceIndexMapper.class);
+
+ Integer rootId;
+ if (resource.getRootId() != null) {
+ ResourceDto root = mapper.selectRootId(resource.getRootId());
+ if (root != null) {
+ rootId = (Integer) ObjectUtils.defaultIfNull(root.getRootId(), root.getId());
+ } else {
+ rootId = resource.getRootId();
}
+ } else {
+ rootId = resource.getId();
+ }
- sqlSession.commit();
+ ResourceIndexDto dto = new ResourceIndexDto()
+ .setResourceId(resource.getId())
+ .setProjectId(rootId)
+ .setNameSize(name.length());
- } finally {
- sqlSession.close();
+ for (int position = 0; position <= normalizedName.length() - MINIMUM_KEY_SIZE; position++) {
+ dto.setPosition(position);
+ dto.setKey(StringUtils.substring(normalizedName, position));
+ mapper.insert(dto);
}
+
+ session.commit();
+ }
+ }
+
+ public void index(String resourceName, int resourceId, int projectId) {
+ SqlSession sqlSession = mybatis.openSession();
+ try {
+ index(new ResourceDto().setId(resourceId).setName(resourceName).setRootId(projectId), sqlSession);
+
+ } finally {
+ sqlSession.close();
+ }
+ }
+
+
+ public void index(ResourceIndexerFilter filter) {
+ TimeProfiler profiler = new TimeProfiler().start("Index resources");
+ final SqlSession sqlSession = mybatis.openSession(ExecutorType.BATCH);
+ try {
+ sqlSession.select("selectResourcesToIndex", filter, new ResultHandler() {
+ public void handleResult(ResultContext context) {
+ ResourceDto resource = (ResourceDto) context.getResultObject();
+ index(resource, sqlSession);
+ }
+ });
+ } finally {
+ sqlSession.close();
+ profiler.stop();
}
}
static String normalize(String input) {
- String result = StringUtils.trim(input);
- result = StringUtils.lowerCase(result);
- return result;
+ return StringUtils.lowerCase(input);
+ }
+
+ public static boolean isValidInput(String input) {
+ return StringUtils.isNotBlank(input) && input.length() >= MINIMUM_SEARCH_SIZE;
}
}
private String key;
private int position;
+ private int nameSize;
private int resourceId;
private int projectId;
return position;
}
- public ResourceIndexDto setPosition(int position) {
- this.position = position;
+ public ResourceIndexDto setPosition(int i) {
+ this.position = i;
return this;
}
return resourceId;
}
- public ResourceIndexDto setResourceId(int resourceId) {
- this.resourceId = resourceId;
+ public ResourceIndexDto setResourceId(int i) {
+ this.resourceId = i;
return this;
}
return projectId;
}
- public ResourceIndexDto setProjectId(int projectId) {
- this.projectId = projectId;
+ public ResourceIndexDto setProjectId(int i) {
+ this.projectId = i;
+ return this;
+ }
+
+ public int getNameSize() {
+ return nameSize;
+ }
+
+ public ResourceIndexDto setNameSize(int i) {
+ this.nameSize = i;
return this;
}
}
public interface ResourceIndexMapper {
- List<ResourceIndexDto> selectLikeKey(String key);
+ List<ResourceIndexDto> selectByKeyword(String keyword);
+
+ ResourceDto selectRootId(int id);
void insert(ResourceIndexDto dto);
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.persistence.resource;
+
+import org.sonar.api.resources.Scopes;
+
+public final class ResourceIndexerFilter {
+ private boolean enabled = true;
+ private String[] scopes = new String[]{Scopes.PROJECT, Scopes.DIRECTORY, Scopes.FILE};
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public String[] getScopes() {
+ return scopes;
+ }
+}
<resultMap id="resourceIndexMap" type="ResourceIndex">
<result property="key" column="kee"/>
<result property="position" column="position"/>
+ <result property="nameSize" column="name_size"/>
<result property="resourceId" column="resource_id"/>
<result property="projectId" column="project_id"/>
</resultMap>
kee, position, resource_id, project_id
</sql>
- <select id="selectLikeKey" parameterType="String" resultMap="resourceIndexMap">
+ <select id="selectByKeyword" parameterType="String" resultMap="resourceIndexMap">
select
<include refid="resourceIndexColumns"/>
from resource_index
order by position asc
</select>
+ <select id="selectResourcesToIndex" parameterType="map" resultType="resource">
+ select id, root_id as "rootId", name
+ from projects
+ where
+ enabled=#{enabled} and
+ copy_resource_id is null and
+ scope in
+ <foreach item="scope" index="index" collection="scopes"
+ open="(" separator="," close=")">#{scope}
+ </foreach>
+ </select>
+
+ <select id="selectRootId" parameterType="int" resultType="resource">
+ select id, root_id as "rootId"
+ from projects
+ where id=#{id}
+ </select>
+
+
<insert id="insert" parameterType="ResourceIndex" useGeneratedKeys="false">
- insert into resource_index (kee, position, resource_id, project_id)
- values (#{key}, #{position}, #{resourceId}, #{projectId})
+ insert into resource_index (kee, position, name_size, resource_id, project_id)
+ values (#{key}, #{position}, #{nameSize}, #{resourceId}, #{projectId})
</insert>
</mapper>
CREATE TABLE "RESOURCE_INDEX" (
"KEE" VARCHAR(100) NOT NULL,
"POSITION" INTEGER NOT NULL,
+ "NAME_SIZE" INTEGER NOT NULL,
"RESOURCE_ID" INTEGER NOT NULL,
"PROJECT_ID" INTEGER NOT NULL
);
+++ /dev/null
-/*
- * Sonar, open source software quality management tool.
- * Copyright (C) 2008-2011 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * Sonar is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * Sonar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with Sonar; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
- */
-package org.sonar.core.plugin;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.picocontainer.MutablePicoContainer;
-import org.picocontainer.PicoContainer;
-import org.sonar.api.BatchExtension;
-import org.sonar.api.ExtensionProvider;
-import org.sonar.api.Plugin;
-import org.sonar.api.ServerExtension;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@Ignore
-public class AbstractPluginRepositoryTest {
-
-// @Test
-// public void testIsType() {
-// assertThat(AbstractPluginRepository.isType(FakeServerExtension.class, ServerExtension.class), is(true));
-// assertThat(AbstractPluginRepository.isType(new FakeServerExtension(), ServerExtension.class), is(true));
-//
-// assertThat(AbstractPluginRepository.isType(FakeBatchExtension.class, ServerExtension.class), is(false));
-// assertThat(AbstractPluginRepository.isType(new FakeBatchExtension(), ServerExtension.class), is(false));
-// assertThat(AbstractPluginRepository.isType(String.class, ServerExtension.class), is(false));
-// assertThat(AbstractPluginRepository.isType("foo", ServerExtension.class), is(false));
-// }
-//
-// @Test
-// public void extensionKeyshouldBeClassNameIfClass() {
-// assertEquals(AbstractPluginRepository.getExtensionKey(FakeServerExtension.class), FakeServerExtension.class);
-// }
-//
-// @Test
-// public void extensionKeyshouldBeUniqueIfObject() {
-// assertThat((String) AbstractPluginRepository.getExtensionKey(new FakeServerExtension()), endsWith("FakeServerExtension-instance"));
-// }
-//
-// @Test
-// public void shouldBeExtensionProvider() {
-// assertThat(AbstractPluginRepository.isExtensionProvider(BProvider.class), is(true));
-// assertThat(AbstractPluginRepository.isExtensionProvider(new BProvider(new A())), is(true));
-// }
-//
-// @Test
-// public void shouldRegisterExtensionProviders() {
-// MutablePicoContainer pico = IocContainer.buildPicoContainer();
-// AbstractPluginRepository repository = new AbstractPluginRepository() {
-// @Override
-// protected boolean shouldRegisterExtension(PicoContainer container, String pluginKey, Object extension) {
-// return isType(extension, ServerExtension.class);
-// }
-// };
-//
-// Plugin plugin = mock(Plugin.class);
-// when(plugin.getExtensions()).thenReturn(Arrays.asList(A.class, BProvider.class, B.class, C.class, D.class));
-// repository.registerPlugin(pico, plugin, "foo");
-// repository.invokeExtensionProviders(pico);
-// pico.start();
-//
-// assertThat(pico.getComponent(A.class), is(A.class));
-// assertThat(pico.getComponent(C.class), is(C.class));
-// assertThat(pico.getComponent(D.class), is(D.class));
-// assertThat(pico.getComponent(C.class).getBees().length, is(3));// 1 in plugin.getExtensions() + 2 created by BProvider
-// assertThat(pico.getComponent(D.class).getBees().length, is(3));
-// assertThat(pico.getComponent(BProvider.class).calls, is(1)); // do not create B instances two times (C and D dependencies)
-// assertThat(pico.getComponents(B.class).size(), is(3));
-// }
-//
-// public static class FakeServerExtension implements ServerExtension {
-// @Override
-// public String toString() {
-// return "instance";
-// }
-// }
-//
-// public static class FakeBatchExtension implements BatchExtension {
-//
-// }
-//
-// public static class A implements ServerExtension {
-// }
-//
-// public static class B implements ServerExtension {
-// private A a;
-//
-// public B(A a) {
-// this.a = a;
-// }
-// }
-//
-//
-// public static class C implements ServerExtension {
-// private B[] bees;
-//
-// public C(B[] bees) {
-// this.bees = bees;
-// }
-//
-// public B[] getBees() {
-// return bees;
-// }
-// }
-//
-// public static class D implements ServerExtension {
-// private B[] bees;
-//
-// public D(B[] bees) {
-// this.bees = bees;
-// }
-//
-// public B[] getBees() {
-// return bees;
-// }
-// }
-//
-// public static class BProvider extends ExtensionProvider implements ServerExtension {
-//
-// private int calls = 0;
-// private A a;
-//
-// public BProvider(A a) {
-// this.a = a;
-// }
-//
-// public Collection<B> provide() {
-// calls++;
-// return Arrays.asList(new B(a), new B(a));
-// }
-// }
-
-
-}
checkTables("testIndex", "resource_index");
}
+ @Test
+ public void testIndexAll() {
+ setupData("testIndexAll");
+
+ dao.index(new ResourceIndexerFilter());
+
+ checkTables("testIndexAll", "resource_index");
+ }
+
}
<level value="WARN"/>
</logger>
+ <!-- set to level DEBUG to log SQL requests executed by MyBatis -->
+ <logger name="java.sql">
+ <level value="WARN"/>
+ </logger>
+
<root>
<level value="INFO"/>
<appender-ref ref="STDOUT"/>
<dataset>
- <resource_index kee="ziputils" position="0" resource_id="10" project_id="8"/>
- <resource_index kee="iputils" position="1" resource_id="10" project_id="8"/>
- <resource_index kee="putils" position="2" resource_id="10" project_id="8"/>
- <resource_index kee="utils" position="3" resource_id="10" project_id="8"/>
- <resource_index kee="tils" position="4" resource_id="10" project_id="8"/>
- <resource_index kee="ils" position="5" resource_id="10" project_id="8"/>
+ <resource_index kee="ziputils" position="0" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="iputils" position="1" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="putils" position="2" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="utils" position="3" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="tils" position="4" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="ils" position="5" name_size="8" resource_id="10" project_id="8"/>
</dataset>
\ No newline at end of file
--- /dev/null
+<dataset>
+
+ <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ root_id="[null]"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]"/>
+
+ <projects long_name="org.struts.RequestContext" id="3" scope="FIL" qualifier="CLA" kee="org.struts:struts:org.struts.RequestContext"
+ name="RequestContext" root_id="1"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]"/>
+
+ <!-- Struts -->
+ <resource_index kee="struts" position="0" name_size="6" resource_id="1" project_id="1"/>
+ <resource_index kee="truts" position="1" name_size="6" resource_id="1" project_id="1"/>
+ <resource_index kee="ruts" position="2" name_size="6" resource_id="1" project_id="1"/>
+ <resource_index kee="uts" position="3" name_size="6" resource_id="1" project_id="1"/>
+
+ <!-- RequestContext -->
+ <resource_index kee="requestcontext" position="0" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="equestcontext" position="1" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="questcontext" position="2" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="uestcontext" position="3" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="estcontext" position="4" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="stcontext" position="5" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="tcontext" position="6" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="context" position="7" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="ontext" position="8" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="ntext" position="9" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="text" position="10" name_size="14" resource_id="3" project_id="1"/>
+ <resource_index kee="ext" position="11" name_size="14" resource_id="3" project_id="1"/>
+</dataset>
--- /dev/null
+<dataset>
+
+ <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ root_id="[null]"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]"/>
+
+ <projects long_name="org.struts.RequestContext" id="3" scope="FIL" qualifier="CLA" kee="org.struts:struts:org.struts.RequestContext"
+ name="RequestContext" root_id="1"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]"/>
+
+</dataset>
<dataset>
<!-- ZipUtils -->
- <resource_index kee="ziputils" position="0" resource_id="10" project_id="8"/>
- <resource_index kee="iputils" position="1" resource_id="10" project_id="8"/>
- <resource_index kee="putils" position="2" resource_id="10" project_id="8"/>
- <resource_index kee="utils" position="3" resource_id="10" project_id="8"/>
- <resource_index kee="tils" position="4" resource_id="10" project_id="8"/>
+ <resource_index kee="ziputils" position="0" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="iputils" position="1" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="putils" position="2" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="utils" position="3" name_size="8" resource_id="10" project_id="8"/>
+ <resource_index kee="tils" position="4" name_size="8" resource_id="10" project_id="8"/>
<!-- DateUtils -->
- <resource_index kee="dateutils" position="0" resource_id="130" project_id="120"/>
- <resource_index kee="ateutils" position="1" resource_id="130" project_id="120"/>
- <resource_index kee="teutils" position="2" resource_id="130" project_id="120"/>
- <resource_index kee="eutils" position="3" resource_id="130" project_id="120"/>
- <resource_index kee="utils" position="4" resource_id="130" project_id="120"/>
- <resource_index kee="tils" position="5" resource_id="130" project_id="120"/>
+ <resource_index kee="dateutils" position="0" name_size="9" resource_id="130" project_id="120"/>
+ <resource_index kee="ateutils" position="1" name_size="9" resource_id="130" project_id="120"/>
+ <resource_index kee="teutils" position="2" name_size="9" resource_id="130" project_id="120"/>
+ <resource_index kee="eutils" position="3" name_size="9" resource_id="130" project_id="120"/>
+ <resource_index kee="utils" position="4" name_size="9" resource_id="130" project_id="120"/>
+ <resource_index kee="tils" position="5" name_size="9" resource_id="130" project_id="120"/>
</dataset>
\ No newline at end of file
import org.sonar.markdown.Markdown;
import org.sonar.persistence.Database;
import org.sonar.persistence.DatabaseMigrator;
+import org.sonar.persistence.resource.ResourceIndexDao;
+import org.sonar.persistence.resource.ResourceIndexerFilter;
import org.sonar.server.configuration.Backup;
import org.sonar.server.configuration.ProfilesManager;
import org.sonar.server.filters.Filter;
public ComponentContainer getContainer() {
return Platform.getInstance().getContainer();
}
+
+
+ // RESOURCE SEARCH ENGINE
+ public void indexResources() {
+ getContainer().getComponentByType(ResourceIndexDao.class).index(new ResourceIndexerFilter());
+ }
+
+ public boolean isValidResourceSearchInput(String input) {
+ return ResourceIndexDao.isValidInput(input);
+ }
}
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# Sonar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+class SearchController < ApplicationController
+
+ SECTION=Navigation::SECTION_HOME
+
+ verify :method => :post, :only => [:reset]
+ before_filter :admin_required, :except => ['index']
+
+ # Do not exceed 1000 because of the Oracle limition on IN statements
+ MAX_RESULTS = 50
+
+ def index
+ @start_time = Time.now
+ @search = params[:s]
+ if @search
+ if java_facade.isValidResourceSearchInput(@search.to_s)
+ normalized_search = @search.downcase
+ @results = ResourceIndex.find(:all,
+ :conditions => ["resource_index.kee like ?", normalized_search + '%'],
+ :order => 'name_size, position')
+
+ @results = select_authorized(:user, @results)
+ @total = @results.size
+ @results = @results[0...MAX_RESULTS]
+
+ @resources_by_id = {}
+ unless @results.empty?
+ Project.find(:all, :conditions => ['id in (?)', @results.map { |resource_index| resource_index.resource_id }]).each do |resource|
+ @resources_by_id[resource.id]=resource
+ end
+ end
+ else
+ flash[:warning]='Please refine your search'
+ end
+ end
+ end
+
+ # Start indexing resources
+ #
+ # curl -v -u admin:admin -X POST http://localhost:9000/search/reset
+ def reset
+ java_facade.indexResources()
+ render :text => 'indexing'
+ end
+end
if date
label = message('since_version_detailed', :params => [mode_param.to_s, date.strftime("%Y %b %d").to_s])
else
- label = message('since_version', :params => mode_param.to_s)
+ label = message('since_version', :params => mode_param.to_s)
end
elsif mode=='previous_analysis'
if !date.nil?
end
url_params={:controller => 'drilldown', :action => 'measures', :metric => metric_key, :id => options[:resource]||@project.id}
-
+
url_for(options.merge(url_params))
end
end
+ def link_to_resource_home(resource, options={})
+ period_index=options[:period]
+ period_index=nil if period_index && period_index<=0
+ if resource.display_dashboard?
+ link_to(options[:name] || resource.name, {:controller => 'dashboard', :action => 'index', :id => (resource.copy_resource_id||resource.id), :period => period_index, :tab => options[:tab], :rule => options[:rule]}, :title => options[:title])
+ else
+ if options[:line]
+ anchor= 'L' + options[:line].to_s
+ end
+ link_to(options[:name] || resource.name, {:controller => 'resource', :action => 'index', :anchor => anchor, :id => resource.id, :period => period_index, :tab => options[:tab], :rule => options[:rule], :metric => options[:metric]}, :popup => ['resource', 'height=800,width=900,scrollbars=1,resizable=1'], :title => options[:title])
+ end
+ end
+
+
#
#
# JFree Eastwood is a partial implementation of Google Chart Api
initial_tooltip=message('click_to_remove_from_favourites')
end
- link_to_remote('', :url => { :controller => 'favourites', :action => 'toggle', :id => resource_id, :elt => html_id},
- :method => :post, :html => {:class => initial_class, :id => html_id, :alt => initial_tooltip, :title => initial_tooltip})
+ link_to_remote('', :url => {:controller => 'favourites', :action => 'toggle', :id => resource_id, :elt => html_id},
+ :method => :post, :html => {:class => initial_class, :id => html_id, :alt => initial_tooltip, :title => initial_tooltip})
end
#
filename = m.tendency.to_s
case m.tendency_qualitative
- when 0
- filename+= '-black'
- when -1
- filename+= '-red'
- when 1
- filename+= '-green'
+ when 0
+ filename+= '-black'
+ when -1
+ filename+= '-red'
+ when 1
+ filename+= '-green'
end
image_tag("tendency/#{filename}-small.png")
end
html = options[:default].to_s if html.nil? && options[:default]
html
end
-
+
#
# Creates a pagination section for the given array (items_array) if its size exceeds the pagination size (default: 20).
# Upon completion of this method, the HTML is returned and the given array contains only the selected elements.
#
def paginate(items_array, options={})
html = items_array.size.to_s + " " + message('results').downcase
-
- page_size = options[:page_size] || 20
+
+ page_size = options[:page_size] || 20
if items_array.size > page_size
# computes the pagination elements
page_id = (params[:page_id] ? params[:page_id].to_i : 1)
from = (page_id-1) * page_size
to = (page_id*page_size)-1
to = items_array.size-1 if to >= items_array.size
-
+
# render the pagination links
html += " | "
html += link_to_if page_id>1, message('paging_previous'), {:overwrite_params => {:page_id => page_id-1}}
html += " "
end
html += link_to_if page_id<page_count, message('paging_next'), {:overwrite_params => {:page_id => 1+page_id}}
-
+
# and adapt the items_array object according to the pagination
items_to_keep = items_array[from..to]
items_array.clear
- items_to_keep.each {|i| items_array << i}
+ items_to_keep.each { |i| items_array << i }
end
-
- html
+
+ html
end
-
+
end
--- /dev/null
+#
+# Sonar, entreprise quality control tool.
+# Copyright (C) 2008-2011 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# Sonar is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# Sonar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with Sonar; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+#
+class ResourceIndex < ActiveRecord::Base
+
+ set_table_name 'resource_index'
+
+ belongs_to :resource, :class_name => 'Project', :foreign_key => 'resource_id'
+ belongs_to :project, :class_name => 'Project', :foreign_key => 'project_id'
+
+ def resource_id_for_authorization
+ project_id
+ end
+end
\ No newline at end of file
--- /dev/null
+<form method="GET" action="index">
+ <input type="text" name="s" id="searchText" value="<%= @search -%>">
+ <input type="submit" value="Search" id="submitSearch">
+</form>
+
+<% if @results %>
+ <table class="data width100" id="searchResults">
+ <thead>
+ <tr>
+ <th colspan="3"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @results.each do |resource_index|
+ resource=@resources_by_id[resource_index.resource_id]
+ %>
+ <tr class="<%= cycle('even', 'odd') -%>">
+ <td class="thin nowrap">
+ <% if resource.display_dashboard? %>
+ <a href="<%= ApplicationController.root_context -%>/components/index/<%= resource.id -%>"><img src="<%= ApplicationController.root_context -%>/images/zoom.png"></a>
+ <% end %>
+ </td>
+ <td class="thin nowrap">
+ <%= qualifier_icon resource -%>
+ </td>
+ <td>
+ <%= link_to_resource_home resource, :name => highlight(resource.name(true), @search) -%>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td colspan="3">
+ <% if @total>@results.size %>
+ <%= @results.size -%> among
+ <% end %>
+ <%= @total -%> results (<%= Time.now-@start_time -%> seconds)
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+<% end %>
+<script type="text/javascript">
+ $('searchText').focus();
+</script>
\ No newline at end of file
create_table 'resource_index', :id => false do |t|
t.column 'kee', :string, :null => false, :limit => 100
t.column 'position', :integer, :null => false
+ t.column 'name_size', :integer, :null => false
t.column 'resource_id', :integer, :null => false
t.column 'project_id', :integer, :null => false
end
add_index 'resource_index', 'kee', :name => 'resource_index_key'
+ add_index 'resource_index', 'resource_id', :name => 'resource_index_rid'
end
end
color: #777;
}
+.highlight {
+ font-weight: bold;
+}
+
.subtitle {
color: #777;
font-size: 85%;
}
div.progress td a {
- display: block; width: 100%; height: 100%;
+ display: block;
+ width: 100%;
+ height: 100%;
}
div.progress td.resolved {
white-space: nowrap;
}
-
/* AUTOCOMPLETE FIELDS */
div.autocomplete {
position: absolute;