projectKey = project.key();
}
- List<ComponentDto> moduleChildren = dbClient.componentDao().findChildrenModulesFromModule(session, query.getModuleKey());
- Map<String, String> moduleUuidsByKey = moduleUuidsByKey(module, moduleChildren);
- Map<String, Long> moduleIdsByKey = moduleIdsByKey(module, moduleChildren);
+ List<ComponentDto> modulesTree = dbClient.componentDao().selectModulesTree(session, module.uuid());
+ Map<String, String> moduleUuidsByKey = moduleUuidsByKey(module, modulesTree);
+ Map<String, Long> moduleIdsByKey = moduleIdsByKey(module, modulesTree);
- List<PropertyDto> moduleChildrenSettings = dbClient.propertiesDao().findChildrenModuleProperties(query.getModuleKey(), session);
- TreeModuleSettings treeModuleSettings = new TreeModuleSettings(moduleUuidsByKey, moduleIdsByKey, moduleChildren, moduleChildrenSettings, module);
+ List<PropertyDto> modulesTreeSettings = dbClient.propertiesDao().selectModulePropertiesTree(module.uuid(), session);
+ TreeModuleSettings treeModuleSettings = new TreeModuleSettings(moduleUuidsByKey, moduleIdsByKey, modulesTree, modulesTreeSettings, module);
addSettingsToChildrenModules(ref, query.getModuleKey(), Maps.<String, String>newHashMap(), treeModuleSettings, hasScanPerm, session);
- addFileData(session, ref, moduleChildren, module.key());
+ addFileData(session, ref, modulesTree, module.uuid());
}
addProfiles(ref, projectKey, query.getProfileName(), session);
moduleKeysByUuid.put(module.uuid(), module.key());
}
- for (FilePathWithHashDto file : dbClient.componentDao().findFilesFromModule(session, moduleKey)) {
+ for (FilePathWithHashDto file : dbClient.componentDao().selectModuleFilesTree(session, moduleKey)) {
FileData fileData = new FileData(file.getSrcHash(), false, null, null, null);
ref.addFileData(moduleKeysByUuid.get(file.getModuleUuid()), file.getPath(), fileData);
}
import com.google.common.collect.Lists;
import org.sonar.api.ServerComponent;
+import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.component.ComponentDto;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
return mapper(session).findSubProjectsByComponentUuids(keys);
}
- public List<ComponentDto> findChildrenModulesFromModule(DbSession session, String moduleKey) {
- return mapper(session).findChildrenModulesFromModule(moduleKey, Scopes.PROJECT);
+ public List<ComponentDto> selectModulesTree(DbSession session, String rootComponentUuid) {
+ return mapper(session).selectModulesTree(rootComponentUuid, Scopes.PROJECT);
}
- public List<FilePathWithHashDto> findFilesFromModule(DbSession session, String moduleKey) {
- return mapper(session).findFilesFromModule(moduleKey, Scopes.FILE);
+ public List<FilePathWithHashDto> selectModuleFilesTree(DbSession session, String rootComponentUuid) {
+ return mapper(session).selectModuleFilesTree(rootComponentUuid, Scopes.FILE);
}
public List<ComponentDto> getByUuids(DbSession session, Collection<String> uuids) {
public List<String> findProjectUuids(DbSession session) {
return mapper(session).findProjectUuids();
}
+
+ public List<Map<String, String>> selectAllViewsAndSubViews(DbSession session) {
+ return mapper(session).selectAllViewsAndSubViews(Qualifiers.VIEW, Qualifiers.SUBVIEW);
+ }
+
+ public List<String> selectProjectsFromView(DbSession session, String projectViewUuid, String viewUuid) {
+ return mapper(session).selectProjectsFromView(projectViewUuid, "%." + viewUuid + ".%", Qualifiers.SUBVIEW);
+ }
}
import org.sonar.server.user.ws.UserPropertiesWs;
import org.sonar.server.user.ws.UsersWs;
import org.sonar.server.util.*;
+import org.sonar.server.view.index.ViewIndexDefinition;
+import org.sonar.server.view.index.ViewIndexer;
import org.sonar.server.ws.ListingWs;
import org.sonar.server.ws.WebServiceEngine;
pico.addSingleton(EventsWs.class);
pico.addSingleton(ComponentCleanerService.class);
+ // views
+ pico.addSingleton(ViewIndexDefinition.class);
+ pico.addSingleton(ViewIndexer.class);
+
// issues
pico.addSingleton(IssueIndexDefinition.class);
pico.addSingleton(IssueIndexer.class);
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.source.index.SourceLineIndexer;
import org.sonar.server.user.index.UserIndexer;
+import org.sonar.server.view.index.ViewIndexer;
import java.util.Date;
private final IssueAuthorizationIndexer issueAuthorizationIndexer;
private final IssueIndexer issueIndexer;
private final UserIndexer userIndexer;
+ private final ViewIndexer viewIndexer;
public IndexSynchronizer(DbClient db, IndexClient index, SourceLineIndexer sourceLineIndexer,
- IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, UserIndexer userIndexer) {
+ IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, UserIndexer userIndexer, ViewIndexer viewIndexer) {
this.db = db;
this.index = index;
this.sourceLineIndexer = sourceLineIndexer;
this.issueAuthorizationIndexer = issueAuthorizationIndexer;
this.issueIndexer = issueIndexer;
this.userIndexer = userIndexer;
+ this.viewIndexer = viewIndexer;
}
public void execute() {
LOG.info("Index users");
userIndexer.index();
+
+ LOG.info("Index views");
+ viewIndexer.index();
}
void synchronize(DbSession session, Dao dao, Index index) {
@Override
protected UserDoc read(ResultSet rs) throws SQLException {
- UserDoc doc = new UserDoc(Maps.<String, Object>newHashMapWithExpectedSize(30));
+ UserDoc doc = new UserDoc(Maps.<String, Object>newHashMapWithExpectedSize(7));
String login = rs.getString(1);
--- /dev/null
+/*
+ * 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.view.index;
+
+import org.sonar.server.search.BaseDoc;
+
+import java.util.List;
+import java.util.Map;
+
+public class ViewDoc extends BaseDoc {
+
+ public ViewDoc(Map<String, Object> fields) {
+ super(fields);
+ }
+
+ public String uuid() {
+ return getField(ViewIndexDefinition.FIELD_UUID);
+ }
+
+ public List<String> projects() {
+ return getField(ViewIndexDefinition.FIELD_PROJECTS);
+ }
+
+ public ViewDoc setUuid(String s) {
+ setField(ViewIndexDefinition.FIELD_UUID, s);
+ return this;
+ }
+
+ public ViewDoc setProjects(List<String> s) {
+ setField(ViewIndexDefinition.FIELD_PROJECTS, s);
+ return this;
+ }
+
+}
--- /dev/null
+/*
+ * 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.view.index;
+
+import com.google.common.collect.ImmutableMap;
+import org.elasticsearch.cluster.metadata.IndexMetaData;
+import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessConstants;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+/**
+ * Definition of ES index "views", including settings and fields.
+ */
+public class ViewIndexDefinition implements IndexDefinition {
+
+ public static final String INDEX = "views";
+
+ public static final String TYPE_VIEW = "view";
+
+ public static final String FIELD_UUID = "uuid";
+ public static final String FIELD_PROJECTS = "projects";
+
+ private final Settings settings;
+
+ public ViewIndexDefinition(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public void define(IndexDefinitionContext context) {
+ NewIndex index = context.create(INDEX);
+
+ // shards
+ boolean clusterMode = settings.getBoolean(ProcessConstants.CLUSTER_ACTIVATE);
+ if (clusterMode) {
+ index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 4);
+ index.getSettings().put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 1);
+ // else keep defaults (one shard)
+ }
+
+ // type "view"
+ NewIndex.NewIndexType mapping = index.createType(TYPE_VIEW);
+ mapping.setAttribute("_id", ImmutableMap.of("path", FIELD_UUID));
+ mapping.stringFieldBuilder(FIELD_UUID).build();
+ mapping.stringFieldBuilder(FIELD_PROJECTS).build();
+ }
+}
--- /dev/null
+/*
+ * 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.view.index;
+
+import com.google.common.collect.Maps;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.BaseIndexer;
+import org.sonar.server.es.BulkIndexer;
+import org.sonar.server.es.EsClient;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+public class ViewIndexer extends BaseIndexer {
+
+ private final DbClient dbClient;
+ private final EsClient esClient;
+
+ public ViewIndexer(DbClient dbClient, EsClient esClient) {
+ super(esClient, 300, ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW);
+ this.dbClient = dbClient;
+ this.esClient = esClient;
+ }
+
+ @Override
+ protected long doIndex(long lastUpdatedAt) {
+ // Index only if index is empty
+ long count = esClient.prepareCount(ViewIndexDefinition.INDEX).setTypes(ViewIndexDefinition.TYPE_VIEW).get().getCount();
+ if (count == 0) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ Map<String, String> viewAndProjectViewUuidMap = newHashMap();
+ for (Map<String, String> viewsMap : dbClient.componentDao().selectAllViewsAndSubViews(dbSession)) {
+ viewAndProjectViewUuidMap.put(viewsMap.get("uuid"), viewsMap.get("projectUuid"));
+ }
+ index(dbSession, viewAndProjectViewUuidMap);
+ } finally {
+ dbSession.close();
+ }
+ }
+ return 0L;
+ }
+
+ public void index(String rootViewUuid) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ Map<String, String> viewAndProjectViewUuidMap = newHashMap();
+ for (ComponentDto viewOrSubView : dbClient.componentDao().selectModulesTree(dbSession, rootViewUuid)) {
+ viewAndProjectViewUuidMap.put(viewOrSubView.uuid(), viewOrSubView.projectUuid());
+ }
+ index(dbSession, viewAndProjectViewUuidMap);
+ } finally {
+ dbSession.close();
+ }
+ }
+
+ private void index(DbSession dbSession, Map<String, String> viewAndProjectViewUuidMap) {
+ final BulkIndexer bulk = new BulkIndexer(esClient, ViewIndexDefinition.INDEX);
+ bulk.start();
+ for (Map.Entry<String, String> entry : viewAndProjectViewUuidMap.entrySet()) {
+ doIndex(dbSession, bulk, entry.getKey(), entry.getValue());
+ }
+ bulk.stop();
+ }
+
+ private void doIndex(DbSession dbSession, BulkIndexer bulk, String uuid, String projectUuid) {
+ List<String> projects = dbClient.componentDao().selectProjectsFromView(dbSession, projectUuid, uuid);
+ bulk.add(newUpsertRequest(new ViewDoc(Maps.<String, Object>newHashMap())
+ .setUuid(uuid)
+ .setProjects(projects)));
+ }
+
+ private UpdateRequest newUpsertRequest(ViewDoc doc) {
+ return new UpdateRequest(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, doc.uuid())
+ .doc(doc.getFields())
+ .upsert(doc.getFields());
+ }
+
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.view.index;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
package org.sonar.server.component.db;
+import com.google.common.collect.ImmutableMap;
import org.apache.ibatis.exceptions.PersistenceException;
import org.junit.After;
import org.junit.Before;
}
@Test
- public void find_children_modules_from_module() throws Exception {
+ public void select_modules_tree() throws Exception {
setupData("multi-modules");
// From root project
- List<ComponentDto> modules = dao.findChildrenModulesFromModule(session, "org.struts:struts");
+ List<ComponentDto> modules = dao.selectModulesTree(session, "ABCD");
assertThat(modules).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI");
// From module
- modules = dao.findChildrenModulesFromModule(session, "org.struts:struts-core");
+ modules = dao.selectModulesTree(session, "EFGH");
assertThat(modules).extracting("uuid").containsOnly("EFGH", "FGHI");
// From sub module
- modules = dao.findChildrenModulesFromModule(session, "org.struts:struts-data");
+ modules = dao.selectModulesTree(session, "FGHI");
assertThat(modules).extracting("uuid").containsOnly("FGHI");
// Folder
- assertThat(dao.findChildrenModulesFromModule(session, "org.struts:struts-core:src/org/struts")).isEmpty();
- assertThat(dao.findChildrenModulesFromModule(session, "unknown")).isEmpty();
+ assertThat(dao.selectModulesTree(session, "GHIJ")).isEmpty();
+ assertThat(dao.selectModulesTree(session, "unknown")).isEmpty();
}
@Test
- public void find_files_from_module() throws Exception {
- setupData("find_files_from_module");
+ public void select_module_files_tree() throws Exception {
+ setupData("select_module_files_tree");
// From root project
- List<FilePathWithHashDto> files = dao.findFilesFromModule(session, "org.struts:struts");
+ List<FilePathWithHashDto> files = dao.selectModuleFilesTree(session, "ABCD");
assertThat(files).extracting("uuid").containsOnly("EFGHI", "HIJK");
assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
// From module
- files = dao.findFilesFromModule(session, "org.struts:struts-core");
+ files = dao.selectModuleFilesTree(session, "EFGH");
assertThat(files).extracting("uuid").containsOnly("EFGHI", "HIJK");
assertThat(files).extracting("moduleUuid").containsOnly("EFGH", "FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcEFGHI", "srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/pom.xml", "src/org/struts/RequestContext.java");
// From sub module
- files = dao.findFilesFromModule(session, "org.struts:struts-data");
+ files = dao.selectModuleFilesTree(session, "FGHI");
assertThat(files).extracting("uuid").containsOnly("HIJK");
assertThat(files).extracting("moduleUuid").containsOnly("FGHI");
assertThat(files).extracting("srcHash").containsOnly("srcHIJK");
assertThat(files).extracting("path").containsOnly("src/org/struts/RequestContext.java");
// From directory
- assertThat(dao.findFilesFromModule(session, "org.struts:struts-core:src/org/struts")).isEmpty();
+ assertThat(dao.selectModuleFilesTree(session, "GHIJ")).isEmpty();
- assertThat(dao.findFilesFromModule(session, "unknown")).isEmpty();
+ assertThat(dao.selectModuleFilesTree(session, "unknown")).isEmpty();
}
@Test
public void synchronize_after() {
dao.synchronizeAfter(session, new Date(0L));
}
+
+ @Test
+ public void select_views_and_sub_views() {
+ setupData("shared_views");
+
+ assertThat(dao.selectAllViewsAndSubViews(session)).contains(
+ ImmutableMap.of("uuid", "ABCD", "projectUuid", "ABCD"),
+ ImmutableMap.of("uuid", "EFGH", "projectUuid", "EFGH"),
+ ImmutableMap.of("uuid", "FGHI", "projectUuid", "EFGH"),
+ ImmutableMap.of("uuid", "IJKL", "projectUuid", "IJKL")
+ );
+ }
+
+ @Test
+ public void select_projects_from_view() {
+ setupData("shared_views");
+
+ assertThat(dao.selectProjectsFromView(session, "ABCD", "ABCD")).containsExactly("BCDE");
+ assertThat(dao.selectProjectsFromView(session, "EFGH", "EFGH")).containsExactly("GHIJ", "HIJK");
+ assertThat(dao.selectProjectsFromView(session, "EFGH", "FGHI")).containsExactly("HIJK");
+ assertThat(dao.selectProjectsFromView(session, "IJKL", "IJKL")).isEmpty();
+ assertThat(dao.selectProjectsFromView(session, "Unknown", "Unknown")).isEmpty();
+ }
}
def.define(context);
assertThat(context.getIndices()).hasSize(1);
- NewIndex issuesIndex = context.getIndices().get("users");
- assertThat(issuesIndex).isNotNull();
- assertThat(issuesIndex.getTypes().keySet()).containsOnly("user");
+ NewIndex index = context.getIndices().get("users");
+ assertThat(index).isNotNull();
+ assertThat(index.getTypes().keySet()).containsOnly("user");
// no cluster by default
- assertThat(issuesIndex.getSettings().get("index.number_of_shards")).isEqualTo("1");
- assertThat(issuesIndex.getSettings().get("index.number_of_replicas")).isEqualTo("0");
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("1");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("0");
}
@Test
UserIndexDefinition def = new UserIndexDefinition(settings);
def.define(context);
- NewIndex issuesIndex = context.getIndices().get("users");
- assertThat(issuesIndex.getSettings().get("index.number_of_shards")).isEqualTo("4");
- assertThat(issuesIndex.getSettings().get("index.number_of_replicas")).isEqualTo("1");
+ NewIndex index = context.getIndices().get("users");
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("4");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("1");
}
}
--- /dev/null
+/*
+ * 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.view.index;
+
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessConstants;
+import org.sonar.server.es.IndexDefinition;
+import org.sonar.server.es.NewIndex;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ViewIndexDefinitionTest {
+
+ IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext();
+
+ @Test
+ public void define() throws Exception {
+ ViewIndexDefinition def = new ViewIndexDefinition(new Settings());
+ def.define(context);
+
+ assertThat(context.getIndices()).hasSize(1);
+ NewIndex index = context.getIndices().get("views");
+ assertThat(index).isNotNull();
+ assertThat(index.getTypes().keySet()).containsOnly("view");
+
+ // no cluster by default
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("1");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("0");
+ }
+
+ @Test
+ public void enable_cluster() throws Exception {
+ Settings settings = new Settings();
+ settings.setProperty(ProcessConstants.CLUSTER_ACTIVATE, true);
+ ViewIndexDefinition def = new ViewIndexDefinition(settings);
+ def.define(context);
+
+ NewIndex index = context.getIndices().get("views");
+ assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("4");
+ assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("1");
+ }
+}
--- /dev/null
+/*
+ * 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.view.index;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.config.Settings;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.EsTester;
+import org.sonar.test.DbTests;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class ViewIndexerTest {
+
+ @Rule
+ public DbTester dbTester = new DbTester();
+
+ @Rule
+ public EsTester esTester = new EsTester().addDefinitions(new ViewIndexDefinition(new Settings()));
+
+ ViewIndexer indexer;
+
+ @Before
+ public void setUp() throws Exception {
+ indexer = new ViewIndexer(new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()), esTester.client());
+ }
+
+ @Test
+ public void index_nothing() throws Exception {
+ indexer.index();
+ assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(0L);
+ }
+
+ @Test
+ public void index() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "index.xml");
+
+ indexer.index();
+
+ List<ViewDoc> docs = esTester.getDocuments("views", "view", ViewDoc.class);
+ assertThat(docs).hasSize(4);
+
+ Map<String, ViewDoc> viewsByUuid = Maps.uniqueIndex(docs, new Function<ViewDoc, String>() {
+ @Override
+ public String apply(ViewDoc doc) {
+ return doc.uuid();
+ }
+ });
+
+ assertThat(viewsByUuid.get("ABCD").projects()).containsOnly("BCDE");
+ assertThat(viewsByUuid.get("EFGH").projects()).containsOnly("GHIJ", "HIJK");
+ assertThat(viewsByUuid.get("FGHI").projects()).containsOnly("HIJK");
+ assertThat(viewsByUuid.get("IJKL").projects()).isEmpty();
+ }
+
+ @Test
+ public void index_only_if_empty_do_nothing_when_index_already_exists() throws Exception {
+ // Some views are not in the db
+ dbTester.prepareDbUnit(getClass(), "index.xml");
+ esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
+ ImmutableMap.<String, Object>of(
+ ViewIndexDefinition.FIELD_UUID, "ABCD",
+ ViewIndexDefinition.FIELD_PROJECTS, newArrayList("BCDE")
+ ));
+
+ indexer.index();
+
+ // ... But they shouldn't be indexed
+ assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(1L);
+ }
+
+ @Test
+ public void index_root_view() throws Exception {
+ dbTester.prepareDbUnit(getClass(), "index.xml");
+
+ indexer.index("EFGH");
+
+ List<ViewDoc> docs = esTester.getDocuments("views", "view", ViewDoc.class);
+ assertThat(docs).hasSize(2);
+
+ Map<String, ViewDoc> viewsByUuid = Maps.uniqueIndex(docs, new Function<ViewDoc, String>() {
+ @Override
+ public String apply(ViewDoc doc) {
+ return doc.uuid();
+ }
+ });
+
+ assertThat(viewsByUuid.get("EFGH").projects()).containsOnly("GHIJ", "HIJK");
+ assertThat(viewsByUuid.get("FGHI").projects()).containsOnly("HIJK");
+ }
+
+}
+++ /dev/null
-<dataset>
-
- <!-- root project -->
- <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
- uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="."
- description="the description" long_name="Apache Struts"
- enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]"/>
-
- <!-- module -->
- <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
- uuid="EFGH" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
- scope="PRJ" qualifier="BRC" long_name="Struts Core"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
-
- <!-- file attached directly on module -->
- <projects id="3" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:pom.xml"
- uuid="EFGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
- name="pom.xml" long_name="pom.xml" root_id="3"
- description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/pom.xml" authorization_updated_at="[null]"/>
-
- <file_sources id="101" project_uuid="ABCD" file_uuid="EFGHI"
- data=",,,,,,,,,,,,,,,unchanged ,,,,,,,,,,,,,,,content "
- line_hashes="lineEFGHI"
- data_hash="dataEFGHI"
- src_hash="srcEFGHI"
- created_at="1412952242000" updated_at="1412952242000"/>
-
- <!-- sub module -->
- <projects id="4" root_id="1" kee="org.struts:struts-data" name="Struts Data"
- uuid="FGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
- scope="PRJ" qualifier="BRC" long_name="Struts Data"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
-
- <!-- directory -->
- <projects id="5" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
- uuid="GHIJ" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
- name="src/org/struts" long_name="org.struts" root_id="3"
- description="[null]"
- enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]"/>
-
- <!-- file -->
- <projects id="6" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
- uuid="HIJK" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
- name="RequestContext.java" long_name="org.struts.RequestContext" root_id="3"
- description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]"/>
-
- <file_sources id="102" project_uuid="ABCD" file_uuid="HIJK"
- data=",,,,,,,,,,,,,,,unchanged ,,,,,,,,,,,,,,,content "
- line_hashes="lineHIJK"
- data_hash="dataHIJK"
- src_hash="srcHIJK"
- created_at="1412952242000" updated_at="1412952242000"/>
-
-</dataset>
--- /dev/null
+<dataset>
+
+ <!-- root project -->
+ <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="."
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]"/>
+
+ <!-- module -->
+ <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
+ uuid="EFGH" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
+ scope="PRJ" qualifier="BRC" long_name="Struts Core"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
+
+ <!-- file attached directly on module -->
+ <projects id="3" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:pom.xml"
+ uuid="EFGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
+ name="pom.xml" long_name="pom.xml" root_id="3"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/pom.xml" authorization_updated_at="[null]"/>
+
+ <file_sources id="101" project_uuid="ABCD" file_uuid="EFGHI"
+ data=",,,,,,,,,,,,,,,unchanged ,,,,,,,,,,,,,,,content "
+ line_hashes="lineEFGHI"
+ data_hash="dataEFGHI"
+ src_hash="srcEFGHI"
+ created_at="1412952242000" updated_at="1412952242000"/>
+
+ <!-- sub module -->
+ <projects id="4" root_id="1" kee="org.struts:struts-data" name="Struts Data"
+ uuid="FGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
+ scope="PRJ" qualifier="BRC" long_name="Struts Data"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]"/>
+
+ <!-- directory -->
+ <projects id="5" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
+ uuid="GHIJ" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
+ name="src/org/struts" long_name="org.struts" root_id="3"
+ description="[null]"
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]"/>
+
+ <!-- file -->
+ <projects id="6" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
+ uuid="HIJK" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
+ name="RequestContext.java" long_name="org.struts.RequestContext" root_id="3"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]"/>
+
+ <file_sources id="102" project_uuid="ABCD" file_uuid="HIJK"
+ data=",,,,,,,,,,,,,,,unchanged ,,,,,,,,,,,,,,,content "
+ line_hashes="lineHIJK"
+ data_hash="dataHIJK"
+ src_hash="srcHIJK"
+ created_at="1412952242000" updated_at="1412952242000"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <!-- Simple View -->
+ <projects id="10" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="MASTER_PROJECT" scope="PRJ" qualifier="VW" name="All projects" path="[null]"/>
+
+ <projects id="110" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD." copy_resource_id="100"
+ kee="MASTER_PROJECTstruts" scope="FIL" qualifier="TRK" name="Struts" path="[null]"/>
+
+ <!-- View with sub view -->
+ <projects id="11" uuid="EFGH" project_uuid="EFGH" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="LANGUAGE_VIEW" scope="PRJ" qualifier="VW" name="By Language" path="[null]"/>
+ <projects id="112" uuid="GHIJ" project_uuid="EFGH" module_uuid="EFGH" module_uuid_path=".EFGH." copy_resource_id="101"
+ kee="VIEW2sslr" scope="FIL" qualifier="TRK" name="SSLR" path="[null]"/>
+
+ <!-- Sub view -->
+ <projects id="13" uuid="FGHI" project_uuid="EFGH" module_uuid="EFGH" module_uuid_path=".EFGH." copy_resource_id="[null]"
+ kee="JAVA_PROJECTS" scope="PRJ" qualifier="SVW" name="Java projects" path="[null]"/>
+ <projects id="113" uuid="HIJK" project_uuid="EFGH" module_uuid="FGHI" module_uuid_path=".EFGH.FGHI." copy_resource_id="100"
+ kee="VIEW2struts" scope="FIL" qualifier="TRK" name="Struts" path="[null]"/>
+
+ <!-- View without project -->
+ <projects id="14" uuid="IJKL" project_uuid="IJKL" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="OTHER" scope="PRJ" qualifier="VW" name="Other projects" path="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <!-- Simple View -->
+ <projects id="10" uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="MASTER_PROJECT" scope="PRJ" qualifier="VW" name="All projects" path="[null]"/>
+
+ <projects id="110" uuid="BCDE" project_uuid="ABCD" module_uuid="ABCD" module_uuid_path=".ABCD." copy_resource_id="100"
+ kee="MASTER_PROJECTstruts" scope="FIL" qualifier="TRK" name="Struts" path="[null]"/>
+
+ <!-- View with sub view -->
+ <projects id="11" uuid="EFGH" project_uuid="EFGH" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="LANGUAGE_VIEW" scope="PRJ" qualifier="VW" name="By Language" path="[null]"/>
+ <projects id="112" uuid="GHIJ" project_uuid="EFGH" module_uuid="EFGH" module_uuid_path=".EFGH." copy_resource_id="101"
+ kee="VIEW2sslr" scope="FIL" qualifier="TRK" name="SSLR" path="[null]"/>
+
+ <!-- Sub view -->
+ <projects id="13" uuid="FGHI" project_uuid="EFGH" module_uuid="EFGH" module_uuid_path=".EFGH." copy_resource_id="[null]"
+ kee="JAVA_PROJECTS" scope="PRJ" qualifier="SVW" name="Java projects" path="[null]"/>
+ <projects id="113" uuid="HIJK" project_uuid="EFGH" module_uuid="FGHI" module_uuid_path=".EFGH.FGHI." copy_resource_id="100"
+ kee="VIEW2struts" scope="FIL" qualifier="TRK" name="Struts" path="[null]"/>
+
+ <!-- View without project -->
+ <projects id="14" uuid="IJKL" project_uuid="IJKL" module_uuid="[null]" module_uuid_path="." copy_resource_id="[null]"
+ kee="OTHER" scope="PRJ" qualifier="VW" name="Other projects" path="[null]"/>
+
+</dataset>
import java.util.Collection;
import java.util.List;
+import java.util.Map;
/**
* @since 4.3
List<String> findProjectUuids();
/**
- * Return all modules children (including itself) from a module key
+ * Return all modules tree (child, grand child, etc. including itself) from a module uuid
*/
- List<ComponentDto> findChildrenModulesFromModule(@Param("moduleKey") String moduleKey, @Param(value = "scope") String scope);
+ List<ComponentDto> selectModulesTree(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope);
/**
- * Return all files children from a module key
+ * Return all files children from a module uuid
*/
- List<FilePathWithHashDto> findFilesFromModule(@Param("moduleKey") String moduleKey, @Param(value = "scope") String scope);
+ List<FilePathWithHashDto> selectModuleFilesTree(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope);
+
+ /**
+ * Return all views and sub views
+ */
+ List<Map<String, String>> selectAllViewsAndSubViews(@Param("viewQualifier") String viewQualifier, @Param("subViewQualifier") String subViewQualifier);
+
+ /**
+ * Return technical projects from a view or a sub-view
+ */
+ List<String> selectProjectsFromView(@Param("projectViewUuid") String projectViewUuid, @Param("viewUuidLikeQuery") String viewUuidLikeQuery,
+ @Param("subViewQualifier") String subViewQualifier);
long countById(long id);
}
}
- public List<PropertyDto> findChildrenModuleProperties(String moduleKey, SqlSession session) {
- return session.getMapper(PropertiesMapper.class).selectChildrenModuleProperties(moduleKey, Scopes.PROJECT);
+ public List<PropertyDto> selectModulePropertiesTree(String moduleUuid, SqlSession session) {
+ return session.getMapper(PropertiesMapper.class).selectModulePropertiesTree(moduleUuid, Scopes.PROJECT);
}
public PropertyDto selectProjectProperty(long resourceId, String propertyKey) {
List<PropertyDto> selectByQuery(@Param("query") PropertyQuery query);
- List<PropertyDto> selectChildrenModuleProperties(@Param("moduleKey") String moduleKey, @Param(value = "scope") String scope);
+ List<PropertyDto> selectModulePropertiesTree(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope);
void update(PropertyDto property);
</where>
</select>
- <select id="findChildrenModulesFromModule" parameterType="map" resultType="Component">
+ <select id="selectModulesTree" parameterType="map" resultType="Component">
SELECT <include refid="componentColumns"/>
FROM projects p
- <include refid="childrenModuleQuery"/>
+ <include refid="modulesTreeQuery"/>
</select>
- <sql id="childrenModuleQuery">
+ <sql id="modulesTreeQuery">
INNER JOIN projects root_project ON root_project.uuid = p.project_uuid AND root_project.enabled = ${_true}
- INNER JOIN projects module ON module.project_uuid = root_project.uuid AND module.enabled = ${_true} AND module.kee = #{moduleKey}
+ INNER JOIN projects module ON module.project_uuid = root_project.uuid AND module.enabled = ${_true} AND module.uuid = #{moduleUuid}
<where>
p.enabled = ${_true}
AND p.scope = #{scope}
</where>
</sql>
- <select id="findFilesFromModule" parameterType="map" resultType="FilePathWithHash">
+ <select id="selectModuleFilesTree" parameterType="map" resultType="FilePathWithHash">
SELECT p.uuid, p.path, p.module_uuid as moduleUuid, fs.src_hash as srcHash
FROM projects p
INNER JOIN file_sources fs ON fs.file_uuid=p.uuid
- <include refid="childrenModuleQuery"/>
+ <include refid="modulesTreeQuery"/>
</select>
<select id="findProjectUuids" resultType="String">
</where>
</select>
+ <select id="selectAllViewsAndSubViews" resultType="hashmap">
+ SELECT v.uuid as "uuid", v.project_uuid as "projectUuid" FROM projects v
+ <where>
+ v.enabled=${_true} AND v.qualifier=#{viewQualifier} OR v.qualifier=#{subViewQualifier}
+ </where>
+ </select>
+
+ <select id="selectProjectsFromView" resultType="String">
+ SELECT p.uuid FROM projects p
+ <where>
+ p.enabled=${_true} AND p.project_uuid=#{projectViewUuid} AND p.qualifier<>#{subViewQualifier}
+ AND p.module_uuid_path LIKE #{viewUuidLikeQuery}
+ </where>
+ </select>
+
<sql id="insertColumns">
(kee, deprecated_kee, uuid, project_uuid, module_uuid, module_uuid_path, name, long_name, qualifier, scope, language, root_id, path, enabled, created_at, authorization_updated_at)
</sql>
where p.resource_id=#{resourceId} and p.user_id is null
</select>
- <select id="selectChildrenModuleProperties" parameterType="String" resultType="Property">
+ <select id="selectModulePropertiesTree" parameterType="String" resultType="Property">
SELECT prop.id as id, prop.prop_key as "key", prop.text_value as value, prop.resource_id as resourceId, prop.user_id as userId
FROM properties prop
- INNER JOIN (SELECT p.id FROM projects p<include refid="org.sonar.core.component.db.ComponentMapper.childrenModuleQuery"/>) modules on modules.id=prop.resource_id
+ INNER JOIN (SELECT p.id FROM projects p<include refid="org.sonar.core.component.db.ComponentMapper.modulesTreeQuery"/>) modules on modules.id=prop.resource_id
WHERE prop.user_id IS NULL
</select>
}
@Test
- public void select_children_module_properties() throws Exception {
- setupData("select_children_module_properties");
+ public void select_module_properties_tree() throws Exception {
+ setupData("select_module_properties_tree");
- List<PropertyDto> properties = dao.findChildrenModuleProperties("org.struts:struts", session);
+ List<PropertyDto> properties = dao.selectModulePropertiesTree("ABCD", session);
assertThat(properties.size(), is(4));
assertThat(properties).extracting("key").containsOnly("struts.one", "core.one", "core.two", "data.one");
assertThat(properties).extracting("value").containsOnly("one", "two");
- properties = dao.findChildrenModuleProperties("org.struts:struts-core", session);
+ properties = dao.selectModulePropertiesTree("EFGH", session);
assertThat(properties.size(), is(3));
assertThat(properties).extracting("key").containsOnly("core.one", "core.two", "data.one");
- properties = dao.findChildrenModuleProperties("org.struts:struts-data", session);
+ properties = dao.selectModulePropertiesTree("FGHI", session);
assertThat(properties.size(), is(1));
assertThat(properties).extracting("key").containsOnly("data.one");
- assertThat(dao.findChildrenModuleProperties("unknown", session).size(), is(0));
+ assertThat(dao.selectModulePropertiesTree("unknown", session).size(), is(0));
}
@Test
+++ /dev/null
-<dataset>
-
- <!-- global -->
- <properties id="1" prop_key="global.one" text_value="one" resource_id="[null]" user_id="[null]"/>
- <properties id="2" prop_key="global.two" text_value="two" resource_id="[null]" user_id="[null]"/>
-
- <!-- org.struts:struts -->
- <properties id="3" prop_key="struts.one" text_value="one" resource_id="1" user_id="[null]"/>
-
- <!-- org.struts:struts-core -->
- <properties id="4" prop_key="core.one" text_value="one" resource_id="2" user_id="[null]"/>
- <properties id="7" prop_key="core.two" text_value="two" resource_id="2" user_id="[null]"/>
-
- <!-- org.struts:struts-data -->
- <properties id="8" prop_key="data.one" text_value="one" resource_id="3" user_id="[null]"/>
-
- <!-- user -->
- <properties id="5" prop_key="user.one" text_value="one" resource_id="[null]" user_id="100"/>
- <properties id="6" prop_key="user.two" text_value="two" resource_id="1" user_id="102"/>
-
-
- <!-- root project -->
- <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
- uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="."
- description="the description" long_name="Apache Struts"
- enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]" />
-
- <!-- module -->
- <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
- uuid="EFGH" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
- scope="PRJ" qualifier="BRC" long_name="Struts Core"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]" />
-
- <!-- sub module -->
- <projects id="3" root_id="1" kee="org.struts:struts-data" name="Struts Data"
- uuid="FGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
- scope="PRJ" qualifier="BRC" long_name="Struts Data"
- description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]" />
-
- <!-- directory -->
- <projects long_name="org.struts" id="4" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
- uuid="GHIJ" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
- name="src/org/struts" root_id="3"
- description="[null]"
- enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]" />
-
- <!-- file -->
- <projects long_name="org.struts.RequestContext" id="5" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
- uuid="HIJK" project_uuid="ABCD" module_uuid="GHIJ" module_uuid_path=".ABCD.EFGH.FGHI."
- name="RequestContext.java" root_id="3"
- description="[null]"
- enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]" />
-
-
-</dataset>
--- /dev/null
+<dataset>
+
+ <!-- global -->
+ <properties id="1" prop_key="global.one" text_value="one" resource_id="[null]" user_id="[null]"/>
+ <properties id="2" prop_key="global.two" text_value="two" resource_id="[null]" user_id="[null]"/>
+
+ <!-- org.struts:struts -->
+ <properties id="3" prop_key="struts.one" text_value="one" resource_id="1" user_id="[null]"/>
+
+ <!-- org.struts:struts-core -->
+ <properties id="4" prop_key="core.one" text_value="one" resource_id="2" user_id="[null]"/>
+ <properties id="7" prop_key="core.two" text_value="two" resource_id="2" user_id="[null]"/>
+
+ <!-- org.struts:struts-data -->
+ <properties id="8" prop_key="data.one" text_value="one" resource_id="3" user_id="[null]"/>
+
+ <!-- user -->
+ <properties id="5" prop_key="user.one" text_value="one" resource_id="[null]" user_id="100"/>
+ <properties id="6" prop_key="user.two" text_value="two" resource_id="1" user_id="102"/>
+
+
+ <!-- root project -->
+ <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts"
+ uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path="."
+ description="the description" long_name="Apache Struts"
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]" authorization_updated_at="[null]" />
+
+ <!-- module -->
+ <projects id="2" root_id="1" kee="org.struts:struts-core" name="Struts Core"
+ uuid="EFGH" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=".ABCD."
+ scope="PRJ" qualifier="BRC" long_name="Struts Core"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]" />
+
+ <!-- sub module -->
+ <projects id="3" root_id="1" kee="org.struts:struts-data" name="Struts Data"
+ uuid="FGHI" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH."
+ scope="PRJ" qualifier="BRC" long_name="Struts Data"
+ description="[null]" enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" authorization_updated_at="[null]" />
+
+ <!-- directory -->
+ <projects long_name="org.struts" id="4" scope="DIR" qualifier="DIR" kee="org.struts:struts-core:src/org/struts"
+ uuid="GHIJ" project_uuid="ABCD" module_uuid="FGHI" module_uuid_path=".ABCD.EFGH.FGHI."
+ name="src/org/struts" root_id="3"
+ description="[null]"
+ enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="src/org/struts" authorization_updated_at="[null]" />
+
+ <!-- file -->
+ <projects long_name="org.struts.RequestContext" id="5" scope="FIL" qualifier="FIL" kee="org.struts:struts-core:src/org/struts/RequestContext.java"
+ uuid="HIJK" project_uuid="ABCD" module_uuid="GHIJ" module_uuid_path=".ABCD.EFGH.FGHI."
+ name="RequestContext.java" root_id="3"
+ description="[null]"
+ enabled="[true]" language="java" copy_resource_id="[null]" person_id="[null]" path="src/org/struts/RequestContext.java" authorization_updated_at="[null]" />
+
+
+</dataset>