private Set<ProjectIssueTypeContext> getContextsForProjects(final Collection<Project> projects) {
   CollectionBuilder<ProjectIssueTypeContext> builder = CollectionBuilder.newBuilder();
   for (Project project : projects) {
     builder.add(
         new ProjectIssueTypeContextImpl(
             new ProjectContextImpl(project.getId()), AllIssueTypesContext.INSTANCE));
   }
   return builder.asMutableSet();
 }
  @Test
  public void testFillOptions() throws Exception {
    final Operand operand = new SingleValueOperand("one");
    final TerminalClause testClause = new TerminalClauseImpl("test", Operator.EQUALS, operand);
    final QueryLiteral literal1 = new QueryLiteral(operand, 1L);
    final QueryLiteral literal2 = new QueryLiteral(operand, 2L);
    final QueryLiteral literal3 = new QueryLiteral(operand, 3L);
    final MockOption option1 = new MockOption(null, null, null, null, null, 25L);
    final MockOption option2 = new MockOption(null, null, null, null, null, 26L);
    final MockOption option3 = new MockOption(null, null, null, null, null, 242L);
    final MockOption option4 = new MockOption(null, null, null, null, null, 27L);

    final List<QueryLiteral> testLiterals = Arrays.asList(literal1, literal2, literal3);

    when(jqlOperandResolver.getValues(theUser, operand, testClause)).thenReturn(testLiterals);

    jqlCascadingSelectLiteralUtil =
        new JqlCascadingSelectLiteralUtil(jqlSelectOptionsUtil) {
          @Override
          public void processPositiveNegativeOptionLiterals(
              final List<QueryLiteral> inputLiterals,
              final List<QueryLiteral> positiveLiterals,
              final List<QueryLiteral> negativeLiterals) {
            assertEquals(testLiterals, inputLiterals);
            positiveLiterals.add(literal1);
            positiveLiterals.add(literal2);
            negativeLiterals.add(literal3);
          }
        };

    when(jqlSelectOptionsUtil.getOptions(customField, literal1, true))
        .thenReturn(Collections.<Option>singletonList(option1));
    when(jqlSelectOptionsUtil.getOptions(customField, literal2, true))
        .thenReturn(Arrays.<Option>asList(option2, option3));
    when(jqlSelectOptionsUtil.getOptions(customField, literal3, true))
        .thenReturn(Arrays.<Option>asList(option4));

    final CascadingSelectCustomFieldClauseContextFactory factory =
        new CascadingSelectCustomFieldClauseContextFactory(
            customField,
            contextSetUtil,
            jqlSelectOptionsUtil,
            fieldConfigSchemeClauseContextUtil,
            jqlOperandResolver,
            jqlCascadingSelectLiteralUtil,
            operatorUsageValidator);

    Set<Option> posOpts = new HashSet<Option>();
    Set<Option> negOpts = new HashSet<Option>();

    factory.fillOptions(theUser, testClause, posOpts, negOpts);

    assertEquals(CollectionBuilder.<Option>newBuilder(option1, option2, option3).asSet(), posOpts);
    assertEquals(CollectionBuilder.<Option>newBuilder(option4).asSet(), negOpts);
  }
  @Test
  public void testGetClauseFromParamsValuesGetFiltered() throws Exception {
    final String clauseName = "clauseName";

    final CustomField customField = mockController.getMock(CustomField.class);
    EasyMock.expect(customField.getName()).andStubReturn("ABC");
    EasyMock.expect(customFieldInputHelper.getUniqueClauseName(theUser, clauseName, "ABC"))
        .andStubReturn(clauseName);

    final CustomFieldParamsImpl customFieldParams = new CustomFieldParamsImpl();
    customFieldParams.addValue(CollectionBuilder.newBuilder("55", "-1", "").asMutableSet());

    final Set<String> expectedFilteredValues = CollectionBuilder.newBuilder("55").asMutableSet();

    final Clause expectedClause = mockController.getMock(Clause.class);

    final IndexedInputHelper indexedInputHelper = mockController.getMock(IndexedInputHelper.class);
    indexedInputHelper.getClauseForNavigatorValues(clauseName, expectedFilteredValues);
    mockController.setReturnValue(expectedClause);

    transformer =
        new VersionCustomFieldSearchInputTransformer(
            clauseName,
            new ClauseNames(clauseName),
            customField,
            indexInfoResolver,
            operandResolver,
            fieldFlagOperandRegistry,
            searchContextVisibilityChecker,
            versionResolver,
            customFieldInputHelper,
            versionManager) {
          @Override
          IndexedInputHelper getIndexedInputHelper() {
            return indexedInputHelper;
          }

          @Override
          boolean isVersionsNotRelatedToProjects(
              final Set<String> versionIdsFromHolder, final FieldValuesHolder fieldValuesHolder) {
            return false;
          }
        };

    mockController.replay();

    FieldValuesHolder holderValues =
        new FieldValuesHolderImpl(MapBuilder.singletonMap(urlParameterName, customFieldParams));
    assertEquals(
        expectedClause, transformer.getClauseFromParams(theUser, customFieldParams, holderValues));

    mockController.verify();
  }
  @Test
  public void testConstructor() throws Exception {
    try {
      new OrderByImpl((Collection<SearchSort>) null);
      fail("Expected an error");
    } catch (IllegalArgumentException e) {
    }

    try {
      new OrderByImpl((SearchSort[]) null);
      fail("Expected an error");
    } catch (IllegalArgumentException e) {
    }

    try {
      new OrderByImpl(new SearchSort("dumpper", SortOrder.DESC), null);
      fail("Expected an error");
    } catch (IllegalArgumentException e) {
    }

    try {
      new OrderByImpl(
          CollectionBuilder.newBuilder(new SearchSort("dump", SortOrder.ASC), null).asList());
      fail("Expected an error.");
    } catch (IllegalArgumentException e) {
    }
  }
  @Test
  public void testAllTypes() {
    final ProjectPermissionPageTab projectPermissionPage =
        jira.gotoLoginPage().loginAsSysAdmin(ProjectPermissionPageTab.class, "CHOC");
    assertEquals("Choc Full Scheme", projectPermissionPage.getSchemeName());
    assertEquals("Choc Full Permission Scheme", projectPermissionPage.getSchemeDescription());

    final Permission permission = projectPermissionPage.getPermissionByName("Create Issues");
    final List<String> entities = permission.getEntities();
    final List<String> expectedEntities =
        CollectionBuilder.newBuilder(
                "Reporter",
                "Group (jira-administrators)",
                "Group (Anyone)",
                "Single User (admin)",
                "Project Lead",
                "Current Assignee",
                "Project Role (Administrators)",
                "User Custom Field Value (User Picker)",
                "Group Custom Field Value (Group Picker)")
            .asList();
    assertEquals(expectedEntities, entities);

    final ProjectSharedBy sharedBy = projectPermissionPage.getSharedBy();
    assertFalse(sharedBy.isPresent());
  }
  @Test
  public void testBadOperatorUsage() throws Exception {
    final TerminalClause testClause = new TerminalClauseImpl("one", Operator.EQUALS, "fine");
    final ClauseContext context1 = createContextForProjects(1, 2);
    final ClauseContext context2 = createContextForProjects(5);
    final ClauseContext context3 = createContextForProjects(1292);

    final FieldConfigScheme scheme = mock(FieldConfigScheme.class);
    when(customField.getConfigurationSchemes()).thenReturn(Arrays.asList(scheme, scheme));

    operatorUsageValidator = mock(OperatorUsageValidator.class);
    when(operatorUsageValidator.check(theUser, testClause)).thenReturn(false);
    when(fieldConfigSchemeClauseContextUtil.getContextForConfigScheme(theUser, scheme))
        .thenReturn(context1, context2);
    when(contextSetUtil.union(CollectionBuilder.newBuilder(context1, context2).asSet()))
        .thenReturn(context3);

    final CascadingSelectCustomFieldClauseContextFactory factory =
        new CascadingSelectCustomFieldClauseContextFactory(
            customField,
            contextSetUtil,
            jqlSelectOptionsUtil,
            fieldConfigSchemeClauseContextUtil,
            jqlOperandResolver,
            jqlCascadingSelectLiteralUtil,
            operatorUsageValidator);

    assertEquals(context3, factory.getClauseContext(theUser, testClause));
  }
  /**
   * Make sure the correct search is performed when theh search request does contain "update date"
   * critera and we have determined that they be included in the comment search.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssuesUpdatedFromToDate() throws Exception {
    final String beforeDuration = "-3d";
    final Date beforeDate = dateSupport.convertToDate(beforeDuration);
    final Date afterDate = createDate(1981, Calendar.JANUARY, 12);
    final User user = new MockUser("me");

    final JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
    builder
        .where()
        .updated()
        .ltEq(beforeDuration)
        .and()
        .updatedAfter(afterDate)
        .and()
        .priority("major");
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(6L, 3L, 13484L, 11111134L).asList();
    final BooleanQuery query = createIssueQuery(issueIds);

    final BooleanQuery dateQuery = new BooleanQuery();
    dateQuery.add(createBeforeQuery(beforeDate), BooleanClause.Occur.MUST);
    dateQuery.add(createAfterQuery(afterDate), BooleanClause.Occur.MUST);

    query.add(dateQuery, BooleanClause.Occur.MUST);

    _testGetRecentComments(issueIds, request, user, true, query);
  }
  @Test
  public void testTerminalClauseTwoSearchHandlersDifferent() throws Exception {
    final TerminalClause input1 = new TerminalClauseImpl("field", Operator.EQUALS, "Value1");
    final TerminalClause input2 = new TerminalClauseImpl("field", Operator.EQUALS, "Value2");
    final SearchHandlerManager manager = mockController.getMock(SearchHandlerManager.class);

    final ClausePermissionHandler permissionHandler =
        mockController.getMock(ClausePermissionHandler.class);
    EasyMock.expect(permissionHandler.sanitise(null, input1)).andReturn(input1);
    EasyMock.expect(permissionHandler.sanitise(null, input1)).andReturn(input2);

    final ClauseHandler handler1 = new MockClauseHandler(null, null, permissionHandler, null);
    final ClauseHandler handler2 = new MockClauseHandler(null, null, permissionHandler, null);

    EasyMock.expect(manager.getClauseHandler((User) null, "field"))
        .andReturn(CollectionBuilder.newBuilder(handler1, handler2).asList());

    final JqlOperandResolver jqlOperandResolver = mockController.getMock(JqlOperandResolver.class);

    mockController.replay();

    ClauseSanitisingVisitor visitor =
        new ClauseSanitisingVisitor(manager, jqlOperandResolver, null) {
          @Override
          TerminalClause sanitiseOperands(final TerminalClause clause) {
            return clause;
          }
        };

    final Clause expected = new OrClause(input1, input2);
    final Clause clause = input1.accept(visitor);
    assertEquals(expected, clause);

    mockController.verify();
  }
  @Test
  public void testGetSearchClauseTwoProjects() throws Exception {
    final CustomFieldParamsImpl customFieldParams = new CustomFieldParamsImpl();
    customFieldParams.addValue(Collections.singleton("123"));
    final Map<String, Object> map =
        MapBuilder.<String, Object>newBuilder()
            .add(urlParameterName, customFieldParams)
            .add(
                SystemSearchConstants.forProject().getUrlParameter(),
                CollectionBuilder.list("1", "2"))
            .toMap();
    FieldValuesHolder values = new FieldValuesHolderImpl(map);
    final AtomicBoolean defaultCalled = new AtomicBoolean(false);
    final DefaultIndexedInputHelper helper =
        new DefaultIndexedInputHelper<Version>(
            indexInfoResolver,
            operandResolver,
            fieldFlagOperandRegistry,
            searchContextVisibilityChecker) {
          @Override
          public Clause getClauseForNavigatorValues(final String clauseName, final Set values) {
            return null;
          }
        };

    transformer =
        new VersionCustomFieldSearchInputTransformer(
            urlParameterName,
            clauseNames,
            customField,
            indexInfoResolver,
            operandResolver,
            fieldFlagOperandRegistry,
            searchContextVisibilityChecker,
            versionResolver,
            customFieldInputHelper,
            versionManager) {
          @Override
          protected DefaultIndexedInputHelper getDefaultIndexedInputHelper() {
            defaultCalled.set(true);
            return helper;
          }

          @Override
          protected IndexedInputHelper getIndexedInputHelper() {
            throw new UnsupportedOperationException(
                "Should not have called through to the special indexed input helper");
          }

          @Override
          protected String getClauseName(final User searcher, final ClauseNames clauseNames) {
            return primaryClauseName;
          }
        };
    replay();

    transformer.getSearchClause(theUser, values);
    assertTrue(defaultCalled.get());
  }
Пример #10
0
 public List<GenericValue> findByField(
     final String entityName,
     final String fieldName,
     final Object fieldValue,
     final String orderBy) {
   return findByAnd(
       entityName, new FieldMap(fieldName, fieldValue), CollectionBuilder.list(orderBy));
 }
Пример #11
0
 static {
   DOC_EXAMPLE = new ProjectRoleBean();
   long id = 10360;
   DOC_EXAMPLE.self = Examples.restURI("project/MKY/role/" + id);
   DOC_EXAMPLE.id = id;
   DOC_EXAMPLE.name = "Developers";
   DOC_EXAMPLE.description = "A project role that represents developers in a project";
   DOC_EXAMPLE.actors = CollectionBuilder.list(RoleActorBean.DOC_EXAMPLE);
 }
  /**
   * Make sure a pure issue key search is given when issues are found. Also, make sure there are no
   * "updated date" critera added to the query.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssues() throws Exception {

    final JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
    builder.where().updatedBetween(createDate(1996, Calendar.SEPTEMBER, 11), null);
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(1L, 2L, 4L, 5L).asList();
    _testGetRecentComments(issueIds, request, null, false, createIssueQuery(issueIds));
  }
  @Test
  public void testNegativeQueryWithPositiveAndNegativeOptions() throws Exception {
    final TerminalClause testClause = new TerminalClauseImpl("one", Operator.NOT_EQUALS, "fine");
    final MockOption option1 = new MockOption(null, null, null, null, null, 25L);
    final MockOption option2 = new MockOption(null, null, null, null, null, 26L);
    final MockOption option2child2 = new MockOption(option2, null, null, null, null, 28L);
    final MockOption option2child1 = new MockOption(option2, null, null, null, null, 27L);
    option2.setChildOptions(Arrays.asList(option2child1, option2child2));

    final ClauseContext context1 = createContextForProjects(1, 2);
    final ClauseContext context2 = createContextForProjects(3);
    final ClauseContext context3 = createContextForProjects(3);

    final FieldConfigScheme scheme = mock(FieldConfigScheme.class);
    when(scheme.isGlobal()).thenReturn(false);

    when(customField.getConfigurationSchemes()).thenReturn(Arrays.asList(scheme, scheme));

    when(fieldConfigSchemeClauseContextUtil.getContextForConfigScheme(theUser, scheme))
        .thenReturn(context1, context2);

    // The second scheme should not be included because it only has options that we are to exclude.
    when(jqlSelectOptionsUtil.getOptionsForScheme(scheme))
        .thenReturn(Arrays.<Option>asList(option1, option2))
        .thenReturn(Arrays.<Option>asList(option2, option2child1, option2child2));

    when(contextSetUtil.union(CollectionBuilder.newBuilder(context1, context2).asSet()))
        .thenReturn(context3);

    final CascadingSelectCustomFieldClauseContextFactory factory =
        new CascadingSelectCustomFieldClauseContextFactory(
            customField,
            contextSetUtil,
            jqlSelectOptionsUtil,
            fieldConfigSchemeClauseContextUtil,
            jqlOperandResolver,
            jqlCascadingSelectLiteralUtil,
            operatorUsageValidator) {
          @Override
          void fillOptions(
              final User user,
              final TerminalClause clause,
              final Set<Option> positiveOption,
              final Set<Option> negativeOption) {

            assertEquals(theUser, user);
            assertEquals(testClause, clause);

            positiveOption.add(option2);
            negativeOption.add(option2child1);
          }
        };

    assertEquals(context3, factory.getClauseContext(theUser, testClause));
  }
  @Test
  public void testGetSorts() throws Exception {
    List<SearchSort> inputSorts =
        CollectionBuilder.newBuilder(new SearchSort("one"), new SearchSort("two")).asMutableList();
    List<SearchSort> expectedSorts = new ArrayList<SearchSort>(inputSorts);

    OrderByImpl impl = new OrderByImpl(inputSorts);
    inputSorts.clear();

    assertEquals(expectedSorts, impl.getSearchSorts());
  }
  @Test
  public void testGetClauseFromParamsFilteredValuesEmpty() throws Exception {
    final CustomFieldParams customFieldParams = mockController.getMock(CustomFieldParams.class);
    customFieldParams.getAllValues();
    mockController.setReturnValue(CollectionBuilder.newBuilder("").asMutableSet());

    final VersionCustomFieldSearchInputTransformer inputTransformer =
        createTransformer("cf[12345]");

    assertNull(inputTransformer.getClauseFromParams(theUser, customFieldParams, null));

    mockController.verify();
  }
  /**
   * Make sure the correct search is performed when theh search request does contain "update date"
   * critera and we have determined that they be included in the comment search.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssuesUpdatedToAbsoluteDate() throws Exception {
    final Date beforeDate = createDate(1994, Calendar.JANUARY, 26);

    final JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
    builder.where().updated().ltEq(beforeDate);
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(5674L).asList();
    final BooleanQuery query = createIssueQuery(issueIds);

    final TermRangeQuery dateQuery = createBeforeQuery(beforeDate);
    query.add(dateQuery, BooleanClause.Occur.MUST);

    _testGetRecentComments(issueIds, request, null, true, query);
  }
  /**
   * Make sure the correct search is performed when theh search request does contain "update date"
   * critera and we have determined that they be included in the comment search.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssuesUpdatedFromAbsoluteDate() throws Exception {
    final Date afterDate = createDate(2006, Calendar.JANUARY, 26);

    builder = JqlQueryBuilder.newBuilder();
    builder.where().updatedAfter(afterDate);
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(5674L).asList();
    final BooleanQuery query = createIssueQuery(issueIds);

    final org.apache.lucene.search.Query dateQuery = createAfterQuery(afterDate);
    query.add(dateQuery, BooleanClause.Occur.MUST);

    _testGetRecentComments(issueIds, request, null, true, query);
  }
  /**
   * Make sure the correct search is performed when theh search request does contain "update date"
   * critera and we have determined that they be included in the comment search.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssuesUpdatedToRelativeDate() throws Exception {
    final String beforeDuration = "-3d";
    final Date beforeDate = dateSupport.convertToDate(beforeDuration);

    final JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
    builder.where().updated().ltEq(beforeDuration);
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(5674L).asList();
    final BooleanQuery query = createIssueQuery(issueIds);

    final TermRangeQuery dateQuery = createBeforeQuery(beforeDate);
    query.add(dateQuery, BooleanClause.Occur.MUST);

    _testGetRecentComments(issueIds, request, null, true, query);
  }
  @Test
  public void testNegativeQueryWithNoOptions() throws Exception {
    final TerminalClause testClause = new TerminalClauseImpl("one", Operator.NOT_IN, "fine");
    final MockOption option2 = new MockOption(null, null, null, null, null, 26L);
    final MockOption option2child2 = new MockOption(option2, null, null, null, null, 28L);
    final MockOption option2child1 = new MockOption(option2, null, null, null, null, 27L);
    option2.setChildOptions(Arrays.asList(option2child1, option2child2));

    final ClauseContext context2 = createContextForProjects(3);
    final ClauseContext context3 = createContextForProjects(64);
    final ClauseContext context4 = createContextForProjects(34938);

    final FieldConfigScheme scheme = mock(FieldConfigScheme.class);
    when(scheme.isGlobal()).thenReturn(false);

    when(customField.getConfigurationSchemes()).thenReturn(Arrays.asList(scheme, scheme));

    when(fieldConfigSchemeClauseContextUtil.getContextForConfigScheme(theUser, scheme))
        .thenReturn(context3, context2);
    when(contextSetUtil.union(CollectionBuilder.newBuilder(context2, context3).asSet()))
        .thenReturn(context4);

    final CascadingSelectCustomFieldClauseContextFactory factory =
        new CascadingSelectCustomFieldClauseContextFactory(
            customField,
            contextSetUtil,
            jqlSelectOptionsUtil,
            fieldConfigSchemeClauseContextUtil,
            jqlOperandResolver,
            jqlCascadingSelectLiteralUtil,
            operatorUsageValidator) {
          @Override
          void fillOptions(
              final User user,
              final TerminalClause clause,
              final Set<Option> positiveOption,
              final Set<Option> negativeOption) {
            assertEquals(theUser, user);
            assertEquals(testClause, clause);
          }
        };

    assertEquals(context4, factory.getClauseContext(theUser, testClause));
  }
  @Test
  public void testNoGeneratedContext() throws Exception {
    final TerminalClause testClause = new TerminalClauseImpl("one", Operator.EQUALS, "fine");
    final MockOption option1 = new MockOption(null, null, null, null, null, 25L);
    final MockOption option2 = new MockOption(null, null, null, null, null, 26L);
    final ClauseContext context1 = createContextForProjects(1, 2);
    final ClauseContext context2 = createContextForProjects(5);

    final FieldConfigScheme scheme = mock(FieldConfigScheme.class);
    when(customField.getConfigurationSchemes()).thenReturn(Arrays.asList(scheme, scheme));
    when(jqlSelectOptionsUtil.getOptionsForScheme(scheme))
        .thenReturn(Arrays.<Option>asList(option1, option2));
    when(fieldConfigSchemeClauseContextUtil.getContextForConfigScheme(theUser, scheme))
        .thenReturn(context1, context2);
    when(contextSetUtil.union(CollectionBuilder.newBuilder(context1, context2).asSet()))
        .thenReturn(new ClauseContextImpl());

    final CascadingSelectCustomFieldClauseContextFactory factory =
        new CascadingSelectCustomFieldClauseContextFactory(
            customField,
            contextSetUtil,
            jqlSelectOptionsUtil,
            fieldConfigSchemeClauseContextUtil,
            jqlOperandResolver,
            jqlCascadingSelectLiteralUtil,
            operatorUsageValidator) {
          @Override
          void fillOptions(
              final User user,
              final TerminalClause clause,
              final Set<Option> positiveOption,
              final Set<Option> negativeOption) {

            assertEquals(theUser, user);
            assertEquals(testClause, clause);

            positiveOption.add(option1);
          }
        };

    assertEquals(
        ClauseContextImpl.createGlobalClauseContext(),
        factory.getClauseContext(theUser, testClause));
  }
  @Test
  public void testGetIndexedValuesStringHappyPath() throws Exception {
    final MockComponent mockComponent1 = new MockComponent(1L, "component1");
    final MockComponent mockComponent2 = new MockComponent(2L, "component1");

    final NameResolver<ProjectComponent> nameResolver = mockController.getMock(NameResolver.class);
    nameResolver.getIdsFromName("component1");
    mockController.setReturnValue(CollectionBuilder.newBuilder("1", "2").asList());
    mockController.replay();

    ComponentIndexInfoResolver resolver = new ComponentIndexInfoResolver(nameResolver);

    final List<String> result = resolver.getIndexedValues("component1");
    assertEquals(2, result.size());
    assertTrue(result.contains(mockComponent1.getId().toString()));
    assertTrue(result.contains(mockComponent2.getId().toString()));

    mockController.verify();
  }
  @Test
  public void testXSS() {
    final ProjectPermissionPageTab projectPermissionPage =
        jira.gotoLoginPage().loginAsSysAdmin(ProjectPermissionPageTab.class, "XSS");
    assertEquals("<script>alert(\"wtf\");</script>", projectPermissionPage.getSchemeName());
    assertEquals("<script>alert(\"wtf\");</script>", projectPermissionPage.getSchemeDescription());
    final Permission permission = projectPermissionPage.getPermissionByName("Administer Projects");

    final List<String> entities = permission.getEntities();
    final List<String> expectedEntities =
        CollectionBuilder.newBuilder("User Custom Field Value (<script>alert(\"wtf\");</script>)")
            .asList();
    assertEquals(expectedEntities, entities);

    final ProjectSharedBy sharedBy = projectPermissionPage.getSharedBy();
    assertTrue(sharedBy.isPresent());
    assertEquals("2 projects", sharedBy.getTriggerText());
    assertEquals(
        Arrays.asList("<script>alert(\"wtf\");</script>", "Another Shared project"),
        sharedBy.getProjects());
  }
  /**
   * Make sure the correct search is performed when theh search request does contain "update date",
   * but that criteria cannot be converted into a filter, that is, when all the "updated date"
   * clauses are not anded together.
   *
   * @throws Exception indicates some unexpected failure.
   */
  @Test
  public void testGetRecentCommentsIssuesBad() throws Exception {
    final String beforeDuration = "-3d";
    final Date afterDate = createDate(1981, Calendar.JANUARY, 12);
    final User user = new MockUser("me");

    final JqlQueryBuilder builder = JqlQueryBuilder.newBuilder();
    builder
        .where()
        .updatedAfter(afterDate)
        .and()
        .sub()
        .priority("minor")
        .or()
        .updated()
        .ltEq(beforeDuration)
        .endsub();
    final SearchRequest request = new SearchRequest(builder.buildQuery());

    final List<Long> issueIds = CollectionBuilder.newBuilder(6L, 3L, 13484L, 11111134L).asList();
    final BooleanQuery query = createIssueQuery(issueIds);

    _testGetRecentComments(issueIds, request, user, true, query);
  }
Пример #24
0
  static {
    try {
      IssueBean issue =
          new IssueBean("EX-1", new URI("http://example.com:8080/jira/rest/api/2.0/issue/EX-1"));
      issue.fields =
          new HashMap<String, FieldBean>() {
            {
              put(UPDATED, FieldBean.create(UPDATED, JiraDataTypes.getType(UPDATED), new Date(1)));
              put(
                  DESCRIPTION,
                  FieldBean.create(
                      DESCRIPTION, JiraDataTypes.getType(DESCRIPTION), "example bug report"));
              put(
                  PROJECT,
                  FieldBean.create(
                      PROJECT, JiraDataTypes.getType(PROJECT), ProjectBean.SHORT_DOC_EXAMPLE_1));
              put(
                  TIMETRACKING,
                  FieldBean.create(
                      TIMETRACKING,
                      JiraDataTypes.getType(TIMETRACKING),
                      new TimeTrackingBean(600L, 200L, 400L)));
            }
          };

      issue.addField(
          IssueFieldConstants.ATTACHMENT,
          FieldBean.create(
              IssueFieldConstants.ATTACHMENT,
              JiraDataTypes.getType(IssueFieldConstants.ATTACHMENT),
              CollectionBuilder.list(AttachmentBean.DOC_EXAMPLE)));
      issue.addField(
          IssueFieldConstants.COMMENT,
          FieldBean.create(
              IssueFieldConstants.COMMENT,
              JiraDataTypes.getType(IssueFieldConstants.COMMENT),
              CollectionBuilder.list(CommentBean.DOC_EXAMPLE)));
      issue.addField(
          IssueFieldConstants.WORKLOG,
          FieldBean.create(
              IssueFieldConstants.WORKLOG,
              JiraDataTypes.getType(IssueFieldConstants.WORKLOG),
              CollectionBuilder.list(WorklogBean.DOC_EXAMPLE)));

      issue.addField(
          "sub-tasks",
          FieldBean.create(
              "sub-tasks",
              JiraDataTypes.getType(IssueFieldConstants.ISSUE_LINKS),
              CollectionBuilder.list(
                  new IssueLinkBean(
                      "EX-2",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/EX-2"),
                      LinkedIssueTypeBean.instance()
                          .name("Sub-task")
                          .direction(LinkedIssueTypeBean.Direction.OUTBOUND)
                          .build()))));
      issue.addField(
          "links",
          FieldBean.create(
              "links",
              JiraDataTypes.getType(IssueFieldConstants.ISSUE_LINKS),
              CollectionBuilder.list(
                  new IssueLinkBean(
                      "PRJ-2",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/PRJ-2"),
                      LinkedIssueTypeBean.instance()
                          .name("Dependent")
                          .description("depends on")
                          .direction(LinkedIssueTypeBean.Direction.OUTBOUND)
                          .build()),
                  new IssueLinkBean(
                      "PRJ-3",
                      new URI("http://example.com:8080/jira/rest/api/2.0/issue/PRJ-3"),
                      LinkedIssueTypeBean.instance()
                          .name("Dependent")
                          .description("is depended by")
                          .direction(LinkedIssueTypeBean.Direction.INBOUND)
                          .build()))));

      issue.addField(
          IssueFieldConstants.WATCHERS,
          FieldBean.create(
              IssueFieldConstants.WATCHERS,
              JiraDataTypes.getType(IssueFieldConstants.WATCHERS),
              WatchersBean.DOC_EXAMPLE));
      // set this as the documentation example
      DOC_EXAMPLE = issue;
    } catch (URISyntaxException e) {
      throw new RuntimeException(e); // never happens
    }
  }
  @Test
  public void testExecuteBuildNumberMissing() throws Exception {
    expect(mockBarrier.await(20, TimeUnit.SECONDS)).andReturn(true);
    expect(mockBeanFactory.getInstance(currentUser)).andReturn(new MockI18nHelper()).anyTimes();

    // called during validation!
    expect(mockPermissionManager.hasPermission(Permissions.SYSTEM_ADMIN, currentUser))
        .andReturn(true);

    // This is called during the first parse of the XML file.  At this stage nothing should have
    // been created yet!
    final MockGenericValue mockGv = new MockGenericValue("someentity");
    expect(mockOfBizDelegator.makeValue(EasyMock.<String>anyObject())).andReturn(mockGv).anyTimes();
    expect(mockAttachmentPathManager.getDefaultAttachmentPath())
        .andReturn(directories.get(0).getAbsolutePath())
        .anyTimes();
    expect(mockIndexPathManager.getDefaultIndexRootPath())
        .andReturn(directories.get(1).getAbsolutePath())
        .anyTimes();
    expect(
            mockLicenseStringFactory.create(
                EasyMock.<String>anyObject(), EasyMock.<String>anyObject()))
        .andStubReturn("");

    // after the first parse check the build number.
    expect(mockBuildUtilsInfo.getCurrentBuildNumber()).andStubReturn("1");
    expect(mockBuildUtilsInfo.getMinimumUpgradableBuildNumber()).andStubReturn("0");

    // after the first parse we also verify the license is good.
    expect(
            mockJiraLicenseService.validate(
                EasyMock.<I18nHelper>anyObject(), EasyMock.<String>anyObject()))
        .andStubReturn(mockValidationResult);
    expect(mockValidationResult.getLicenseVersion()).andStubReturn(2);
    expect(mockValidationResult.getErrorCollection()).andStubReturn(new SimpleErrorCollection());

    // this gets called during shutdownAndFlushAsyncServices.  After parse and before the import.
    // This shuts down
    // the scheduler
    expect(mockScheduler.isShutdown()).andReturn(false);
    mockScheduler.shutdown();
    mockMailQueue.sendBuffer();
    expect(mockTaskManager.shutdownAndWait(5)).andReturn(true);

    // Expect AO to be cleared.
    backup.clear();

    // Once the import is running one of the first things to do is to clear out the old database
    // values.
    expect(mockOfBizDelegator.getModelReader()).andReturn(mockModelReader);
    expect(mockModelReader.getEntityNames())
        .andReturn(CollectionBuilder.<String>list("Issue", "User"));
    expect(mockModelReader.getModelEntity("Issue")).andReturn(new ModelEntity());
    expect(mockOfBizDelegator.removeByAnd("Issue", Collections.<String, Object>emptyMap()))
        .andReturn(10);
    expect(mockModelReader.getModelEntity("User")).andReturn(new ModelEntity());
    expect(mockOfBizDelegator.removeByAnd("User", Collections.<String, Object>emptyMap()))
        .andReturn(5);

    // then we go through and create all our GVs (already mocked out during the first parse above)

    // once everything's been imported need to refresh the ofbiz sequencer and check for data
    // consistency.
    mockOfBizDelegator.refreshSequencer();
    mockConsistencyChecker.checkDataConsistency();

    // after the consistency check lets do the upgrade
    expect(mockUpgradeManager.doUpgradeIfNeededAndAllowed(null))
        .andReturn(Collections.<String>emptyList());

    // now do a reindex
    mockIndexManager.deactivate();
    expect(mockIndexManager.size()).andReturn(5);
    expect(mockIndexManager.activate((Context) notNull())).andReturn(1L);

    // raise the JiraStartedEvent
    mockPluginEventManager.broadcast(EasyMock.<JiraStartedEvent>anyObject());

    // finally we can restart the scheduler!
    expect(
            mockScheduler.scheduleJob(
                EasyMock.<JobDetail>anyObject(), EasyMock.<Trigger>anyObject()))
        .andReturn(new Date())
        .anyTimes();
    mockScheduler.start();

    final String filePath = getDataFilePath("jira-export-test-no-build-number.xml");
    final DataImportParams params = new DataImportParams.Builder(filePath).build();

    // Finally everything's mocked out.  Run the import!
    executeTest(params, true, DataImportService.ImportError.NONE);

    // create() should have been called on our GVs
    assertTrue(mockGv.isCreated());
    // the world should have been rebuilt!
    assertTrue(((MockDataImportDependencies) mockDependencies).globalRefreshCalled);
  }
/**
 * SQL Interceptor that detects changes to the database that aren't xsrf protected
 *
 * @since v4.1
 */
public class XsrfVulnerabilityDetectionSQLInterceptor implements SQLConnectionInterceptor {
  private static final Logger log =
      Logger.getLogger(XsrfVulnerabilityDetectionSQLInterceptor.class);
  private static final String XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE =
      "XsrfVulnerabilityDetectionSQLInterceptorDone";

  @Override
  public void onConnectionTaken(Connection connection, ConnectionPoolState connectionPoolState) {}

  @Override
  public void onConnectionReplaced(
      Connection connection, ConnectionPoolState connectionPoolState) {}

  public void beforeExecution(
      final String sqlString, final List<String> parameterValues, final Statement statement) {}

  public void afterSuccessfulExecution(
      final String sqlString,
      final List<String> parameterValues,
      final Statement statement,
      final ResultSet resultSet,
      final int rowsUpdated) {
    afterExecutionImpl(sqlString);
  }

  public void onException(
      final String sqlString,
      final List<String> parameterValues,
      final Statement statement,
      final SQLException sqlException) {
    afterExecutionImpl(sqlString);
  }

  private boolean isMutatingSQL(String sql) {
    String sqlString = sql.toUpperCase();
    return sqlString.startsWith("INSERT")
        || sqlString.startsWith("UPDATE")
        || sqlString.startsWith("DELETE");
  }

  private void afterExecutionImpl(final String sqlString) {
    if (JiraSystemProperties.getInstance().isXsrfDiagnostics()) {
      final String requestURL = MDC.get("jira.request.url");
      if (isMutatingSQL(sqlString)) {
        HttpServletRequest request = ActionContext.getRequest();
        if (request != null
            && request.getAttribute(XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE) == null) {
          // setting this into the request will make things a lot faster
          request.setAttribute(XSRF_VULNERABILITY_DETECTION_SQLINTERCEPTOR_DONE, "true");
          CallStack callStack = new CallStack();
          if (callStack.hasMethodsWeAreInterestedIn() && !callStack.isProtectedAction()) {
            log.error("XSRF VULNERABILITY DETECTED");
            log.error("requestURL: " + requestURL);
            log.error("sql: " + sqlString);
            log.error("CallStack:", callStack);
          }
        }
      }
    }
  }

  static final List<String> methodsToIgnore =
      CollectionBuilder.list(
          "com.atlassian.sal.jira.lifecycle.JiraLifecycleManager.onJiraStart",
          "com.atlassian.jira.security.login.LoginStoreImpl.recordLoginAttempt",
          "com.atlassian.jira.user.DefaultUserHistoryManager.addItemToHistory");

  static final List<String> actionWhiteList = new ArrayList<String>();

  static {
    if (JiraSystemProperties.isXsrfDetectionCheckRequired()) {
      log.setLevel(Level.INFO);
    }

    LineIterator iterator =
        IOUtils.lineIterator(
            new InputStreamReader(
                XsrfVulnerabilityDetectionSQLInterceptor.class.getResourceAsStream(
                    "/security/xsrf/xsrf-white-list.txt")));
    for (; iterator.hasNext(); ) {
      String line = ((String) iterator.next()).trim();
      if (line.length() > 0 && !line.startsWith("#")) {
        actionWhiteList.add(line);
      }
    }
  }

  private static class CallStack extends RuntimeException {
    public boolean hasMethodsWeAreInterestedIn() {

      for (StackTraceElement element : getStackTrace()) {
        String method = element.getClassName() + "." + element.getMethodName();
        if (methodsToIgnore.contains(method)) {
          return false;
        }
      }

      return true;
    }

    public boolean isProtectedAction() {
      boolean isAnnotated = false;

      StackTraceElement elements[] = getStackTrace();
      for (int i = 0; i < elements.length; i++) {
        StackTraceElement element = elements[i];
        if (isActionSupport_execute(element)) {

          StackTraceElement action = findActionStackTraceElement(elements, i);
          // in OSGI land its possible that we cant see the method in play so
          // if we cant access it then we cant check it
          if (action != null) {

            final String className = action.getClassName();

            try {
              final Class<?> aClass = Class.forName(action.getClassName());
              final Method method = getMethod(aClass, action.getMethodName());
              // in OGSI land its possible that we cant see the method in play so
              // if we cant access it then we cant check it
              if (method != null) {
                isAnnotated = method.isAnnotationPresent(RequiresXsrfCheck.class);
                final String actionMethodName = action.getMethodName();
                final String actionName = className + "." + actionMethodName;
                log.info("ACTION: " + actionName + " PROTECTED: " + isAnnotated);

                final boolean isActionInWhiteList = isActionInWhiteList(aClass);
                if (!isAnnotated) {
                  if (isActionInWhiteList) {
                    // its mutated something and its in the white list of good actions.  Something
                    // is rotten in Denmark!
                    throw new RuntimeException("XSRF white list failure");
                  }
                } else {
                  if (!isActionInWhiteList) {
                    // its a XSRF annotated method but its not in the white list.  We have missed
                    // putting it in the white list
                    throw new RuntimeException(
                        "ACTION: "
                            + actionName
                            + " has XSRF annotated but its not in the whitelist");
                  }
                }
              }
            } catch (ClassNotFoundException e) {
              // ignored
            }
            break; // out of the loop
          }
        }
      }
      return isAnnotated;
    }

    private StackTraceElement findActionStackTraceElement(
        final StackTraceElement[] elements, final int i) {
      StackTraceElement foundElement = null;
      // if the next method is ActionSupport.invokeCommand we need to search up the stack trace
      // until we find a doXXXX method
      StackTraceElement element = elements[i - 1];
      if (isActionSupport_invokeCommand(element)) {
        for (int j = i; j >= 0; j--) {
          element = elements[j];
          if (isActionDoMethod(element)) {
            foundElement = element;
            break;
          }
        }
      }
      return foundElement;
    }

    private boolean isActionSupport_invokeCommand(final StackTraceElement element) {
      return ActionSupport.class.getName().equals(element.getClassName())
          && "invokeCommand".equals(element.getMethodName());
    }

    private boolean isActionSupport_execute(final StackTraceElement element) {
      return ActionSupport.class.getName().equals(element.getClassName())
          && "execute".equals(element.getMethodName());
    }

    private boolean isActionDoMethod(final StackTraceElement element) {
      boolean isok = ActionSupport.class.isAssignableFrom(getClassOfElement(element));
      isok = isok && element.getMethodName().startsWith("do");
      return isok;
    }

    private Class getClassOfElement(final StackTraceElement element) {
      try {
        return Class.forName(element.getClassName());
      } catch (ClassNotFoundException e) {
        return e.getClass();
      }
    }

    private boolean isActionInWhiteList(final Class<?> aClass) {
      // complex name first
      boolean isActionInWhiteList = actionWhiteList.contains(aClass.getName());
      if (!isActionInWhiteList) {
        // simple name last
        isActionInWhiteList = actionWhiteList.contains(aClass.getSimpleName());
      }
      return isActionInWhiteList;
    }

    /**
     * Finds the declared method on the provided class. If the method is not declared on the class,
     * we search recursively up the inheritance hierarchy, stopping at {@link
     * com.atlassian.jira.web.action.JiraWebActionSupport} or {@link Object}.
     *
     * @param clazz the class
     * @param methodName the method name to find
     * @return the method on the class; null if it could not be found.
     */
    private Method getMethod(final Class<?> clazz, final String methodName) {
      try {
        return clazz.getDeclaredMethod(methodName);
      } catch (NoSuchMethodException e) {
        if (clazz.equals(JiraWebActionSupport.class) || clazz.equals(Object.class)) {
          return null;
        } else {
          return getMethod(clazz.getSuperclass(), methodName);
        }
      }
    }
  }
}
Пример #27
0
public class DefaultOfBizDelegator implements OfBizDelegator {
  private static final Logger log = Logger.getLogger(DefaultOfBizDelegator.class);
  private static final int DEFAULT_DATABASE_QUERY_BATCH_SIZE = 100;
  private static final String COUNT_FIELD_NAME = "count";
  private static final Collection<String> UNSUPPORTED_TYPES_FOR_FINDBY =
      CollectionBuilder.newBuilder("very-long", "extremely-long", "text", "blob").asCollection();

  public static int getQueryBatchSize() {
    String size = null;
    try {
      size =
          ComponentAccessor.getApplicationProperties()
              .getDefaultBackedString(APKeys.DATABASE_QUERY_BATCH_SIZE);
      return Integer.parseInt(size);
    } catch (final NumberFormatException e) {
      log.error(
          "Error while converting database query batch size '"
              + size
              + "'. Using default value of "
              + DEFAULT_DATABASE_QUERY_BATCH_SIZE);
      return DEFAULT_DATABASE_QUERY_BATCH_SIZE;
    }
  }

  private final DelegatorInterface delegatorInterface;
  private final FieldSupportValidator findByValidator;

  public DefaultOfBizDelegator(final DelegatorInterface delegatorInterface) {
    this.delegatorInterface = delegatorInterface;
    findByValidator =
        new FieldSupportValidator("findBy", UNSUPPORTED_TYPES_FOR_FINDBY, new FieldTypeResolver());
  }

  public List<GenericValue> findByField(
      final String entityName, final String fieldName, final Object fieldValue) {
    return findByAnd(entityName, new FieldMap(fieldName, fieldValue));
  }

  public List<GenericValue> findByField(
      final String entityName,
      final String fieldName,
      final Object fieldValue,
      final String orderBy) {
    return findByAnd(
        entityName, new FieldMap(fieldName, fieldValue), CollectionBuilder.list(orderBy));
  }

  public List<GenericValue> findByAnd(final String entityName, final Map<String, ?> fields)
      throws DataAccessException {
    findByValidator.checkAll(entityName, fields.keySet());
    try {
      return delegatorInterface.findByAnd(entityName, fields);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findByAnd(
      final String entityName, final Map<String, ?> fields, final List<String> orderBy)
      throws DataAccessException {
    findByValidator.checkAll(entityName, fields.keySet());
    try {
      return delegatorInterface.findByAnd(entityName, fields, orderBy);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findByAnd(
      final String entityName, final List<EntityCondition> expressions) throws DataAccessException {
    // cannot check EntityCondition instances as they don't give us a where condition
    try {
      return delegatorInterface.findByAnd(entityName, expressions);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findByOr(
      final String entityName, final List expressions, final List orderBy)
      throws DataAccessException {
    try {
      if (orderBy != null) {
        return delegatorInterface.findByOr(entityName, expressions, orderBy);
      } else {
        return delegatorInterface.findByOr(entityName, expressions);
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findByLike(final String s, final Map<String, ?> map)
      throws DataAccessException {
    return findByLike(s, map, Collections.<String>emptyList());
  }

  public List<GenericValue> findByLike(
      final String s, final Map<String, ?> map, final List<String> orderBy)
      throws DataAccessException {
    try {
      return delegatorInterface.findByLike(s, map, orderBy);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public void removeAll(final List<GenericValue> genericValues) throws DataAccessException {
    try {
      delegatorInterface.removeAll(genericValues, false);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public int removeByCondition(String entityName, EntityCondition condition)
      throws DataAccessException {
    try {
      return delegatorInterface.removeByCondition(entityName, condition, false);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findByCondition(
      final String entityName,
      final EntityCondition entityCondition,
      final Collection<String> fieldsToSelect) {
    return findByCondition(
        entityName, entityCondition, fieldsToSelect, Collections.<String>emptyList());
  }

  public List<GenericValue> findByCondition(
      final String entityName,
      final EntityCondition entityCondition,
      final Collection<String> fieldsToSelect,
      final List<String> orderBy) {
    try {
      return delegatorInterface.findByCondition(
          entityName, entityCondition, fieldsToSelect, orderBy);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public int removeByOr(final String entityName, final String entityId, final List<Long> ids)
      throws DataAccessException, GenericModelException {
    int result = 0;

    final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

    if (modelEntity == null) {
      throw new GenericModelException("The entityName passed in was not valid: " + entityName);
    } else if (!modelEntity.isField(entityId)) {
      throw new GenericModelException(
          "The entityId passed in was not valid for the given entity: " + entityId);
    }
    final ModelField modelField = modelEntity.getField(entityId);

    try {
      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);
      // Generate SQL
      final StringBuilder removeSql = new StringBuilder("DELETE FROM ");

      removeSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      removeSql.append(" WHERE ");
      removeSql.append(modelField.getColName());
      removeSql.append(" IN (");

      final int idsSize = ids.size();
      final ArrayList<Long> idParams = new ArrayList<Long>();
      StringBuilder idClause = new StringBuilder();

      // batch the update
      final int batchSize = getQueryBatchSize();
      int batchIndex = 0;
      for (int i = 0; i < idsSize; i++) {
        idParams.add(ids.get(i));
        idClause.append("?");

        final boolean isEndOfBatch = (batchIndex == batchSize - 1);
        final boolean isEndOfIdList = (i == idsSize - 1);

        if (isEndOfBatch || isEndOfIdList) {
          final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
          // finish batch
          idClause.append(")");
          try {
            processor.prepareStatement(removeSql.toString() + idClause.toString());
            for (final Long idParam : idParams) {
              processor.setValue(idParam);
            }
            // execute update
            result += processor.executeUpdate();

            // clean-up for the next batch
            idParams.clear();
            idClause = new StringBuilder();
            batchIndex = 0;
          } finally {
            try {
              processor.close();
            } catch (final GenericDataSourceException e) {
              log.warn("Could not close the SQLProcessor", e);
            }
          }
        } else {
          // add to this batch
          idClause.append(", ");
          batchIndex++;
        }
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final SQLException e) {
      throw new DataAccessException(e);
    }

    return result;
  }

  public int removeByAnd(final String entityName, final Map map) throws DataAccessException {
    try {
      return delegatorInterface.removeByAnd(entityName, map);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public int removeById(String entityName, Long id) {
    return removeByAnd(entityName, FieldMap.build("id", id));
  }

  public int removeValue(final GenericValue value) throws DataAccessException {
    try {
      return delegatorInterface.removeValue(value);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public void storeAll(final List genericValues) throws DataAccessException {
    try {
      delegatorInterface.storeAll(genericValues);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findAll(final String s) {
    try {
      return delegatorInterface.findAll(s);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public List<GenericValue> findAll(final String s, final List sortOrder)
      throws DataAccessException {
    try {
      return delegatorInterface.findAll(s, sortOrder);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public void store(final GenericValue gv) throws DataAccessException {
    try {
      delegatorInterface.store(gv);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public GenericValue createValue(final String entityName, final Map<String, Object> fields) {
    try {
      final Map<String, Object> params =
          (fields == null) ? new HashMap<String, Object>(2) : new HashMap<String, Object>(fields);
      if (params.get("id") == null) {
        final Long id = delegatorInterface.getNextSeqId(entityName);
        params.put("id", id);
      }

      final GenericValue v = delegatorInterface.makeValue(entityName, params);
      v.create();
      return v;
    } catch (final GenericEntityException ex) {
      throw new DataAccessException(ex);
    }
  }

  @Override
  public void createValueWithoutId(final String entityName, final Map<String, Object> fields)
      throws DataAccessException {
    try {
      final GenericValue v = delegatorInterface.makeValue(entityName, fields);
      v.create();
    } catch (final GenericEntityException ex) {
      throw new DataAccessException(ex);
    }
  }

  public GenericValue makeValue(final String entityName) {
    return delegatorInterface.makeValue(entityName, null);
  }

  @Override
  public GenericValue makeValue(String entityName, Map<String, Object> fields) {
    return delegatorInterface.makeValue(entityName, fields);
  }

  @Override
  public GenericValue findById(String entityName, Long id) throws DataAccessException {
    return findByPrimaryKey(entityName, id);
  }

  public GenericValue findByPrimaryKey(final String entityName, final Long id) {
    // Build up the Map for the caller
    final Map<String, Object> fields = new HashMap<String, Object>(2);
    fields.put("id", id);
    // and delegate to the original findByPrimaryKey() method.
    return findByPrimaryKey(entityName, fields);
  }

  public GenericValue findByPrimaryKey(final String entityName, final Map<String, ?> fields) {
    final long start = System.currentTimeMillis();
    try {
      return delegatorInterface.findByPrimaryKey(entityName, fields);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } finally {
      ThreadLocalQueryProfiler.store(
          "OfBizDelegator", "findByPrimaryKey", System.currentTimeMillis() - start);
    }
  }

  public List<GenericValue> getRelated(final String relationName, final GenericValue gv) {
    try {
      return delegatorInterface.getRelated(relationName, gv);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public List<GenericValue> getRelated(
      final String relationName, final GenericValue gv, final List<String> orderBy)
      throws DataAccessException {
    try {
      return delegatorInterface.getRelatedOrderBy(relationName, orderBy, gv);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public long getCount(final String entityName) {
    // run a count with no where clause
    return getCountByAnd(entityName, new FieldMap());
  }

  @Override
  public long getCountByAnd(final String entityName, final Map<String, ?> fields) {
    try {
      final EntityCondition condition = new EntityFieldMap(fields, EntityOperator.AND);
      final GenericValue countGV =
          EntityUtil.getOnly(
              delegatorInterface.findByCondition(
                  entityName + "Count", condition, ImmutableList.of(COUNT_FIELD_NAME), null));
      return countGV.getLong(COUNT_FIELD_NAME);
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public OfBizListIterator findListIteratorByCondition(
      final String entityType, final EntityCondition condition) {
    try {
      return new DefaultOfBizListIterator(
          delegatorInterface.findListIteratorByCondition(entityType, condition, null, null));
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  /**
   * Always close the iterator returned from this method when finished.
   *
   * @return OfBizListIterator
   */
  public OfBizListIterator findListIteratorByCondition(
      final String entityName,
      final EntityCondition whereEntityCondition,
      final EntityCondition havingEntityCondition,
      final Collection fieldsToSelect,
      final List orderBy,
      final EntityFindOptions entityFindOptions) {
    try {
      return new DefaultOfBizListIterator(
          delegatorInterface.findListIteratorByCondition(
              entityName,
              whereEntityCondition,
              havingEntityCondition,
              fieldsToSelect,
              orderBy,
              entityFindOptions));
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  public int bulkUpdateByPrimaryKey(
      final String entityName, final Map<String, ?> updateValues, final List<Long> keys) {
    int result = 0;

    if ((entityName == null)
        || (updateValues == null)
        || updateValues.isEmpty()
        || (keys == null)
        || keys.isEmpty()) {
      return 0;
    }

    try {
      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final List<String> pks = modelEntity.getPkFieldNames();
      if (pks.size() != 1) {
        throw new DataAccessException(
            "BulkUpdateByPrimaryKey only works for single column keys at this moment.");
      }
      final String pkName = pks.get(0);

      final Updater updater =
          new Updater(
              ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName()),
              entityName);
      final List<Updater.Value> params = new ArrayList<Updater.Value>();

      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");
      // generate the update sql
      for (final Iterator<String> iterator = updateValues.keySet().iterator();
          iterator.hasNext(); ) {
        final String column = iterator.next();
        updateSql.append(" ");
        final ModelField field = modelEntity.getField(column);
        updateSql.append(field.getColName());
        updateSql.append(" = ");
        params.add(updater.create(field, updateValues.get(column)));
        updateSql.append("? ");
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      // generate the where clause
      updateSql.append(" WHERE ");

      // batch the update
      final int batchSize = getQueryBatchSize();

      int currentIndex = 0;

      while (currentIndex < keys.size()) {
        int i = 0;
        final StringBuilder idClause = new StringBuilder();
        final ArrayList<Long> idParams = new ArrayList<Long>();
        for (final Iterator<Long> iterator = keys.subList(currentIndex, keys.size()).iterator();
            iterator.hasNext() && (i < batchSize);
            i++) {
          final Long key = iterator.next();
          idClause.append(" ");
          idClause.append(pkName);
          idClause.append(" = ");
          idParams.add(key);
          idClause.append("? ");

          if (iterator.hasNext() && ((i + 1) < batchSize)) {
            idClause.append(" or ");
          }
        }

        final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
        processor.prepareStatement(updateSql.toString() + idClause.toString());
        for (final Updater.Value param : params) {
          param.setValue(processor);
        }
        for (final Long idParam : idParams) {
          processor.setValue(idParam);
        }

        try {
          result = processor.executeUpdate();
        } finally {
          processor.close();
        }
        currentIndex += i;
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final SQLException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }
    return result;
  }

  public int bulkUpdateByAnd(
      final String entityName, final Map<String, ?> updateValues, final Map<String, ?> criteria) {
    int result = 0;

    if ((entityName == null) || (updateValues == null) || updateValues.isEmpty()) {
      return 0;
    }

    try {
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);

      final ModelFieldTypeReader modelFieldTypeReader =
          ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName());

      final ArrayList<EntityConditionParam> params = new ArrayList<EntityConditionParam>();

      // generate the update sql
      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");

      if (!modelEntity.areFields(updateValues.keySet())) {
        throw new GenericModelException(
            "At least one of the passed fields for update is not valid: "
                + updateValues.keySet().toString());
      }

      for (final Iterator<String> iterator = updateValues.keySet().iterator();
          iterator.hasNext(); ) {
        final String fieldName = iterator.next();
        updateSql.append(" ");
        final ModelField modelField = modelEntity.getField(fieldName);
        updateSql.append(modelField.getColName());
        updateSql.append(" = ");
        params.add(new EntityConditionParam(modelField, updateValues.get(fieldName)));
        updateSql.append("? ");
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      if ((criteria != null) && !criteria.isEmpty()) {
        if (!modelEntity.areFields(criteria.keySet())) {
          throw new GenericModelException(
              "At least one of the passed fields is not valid: " + criteria.keySet().toString());
        }

        // generate the where clause
        final EntityFieldMap entityCondition = new EntityFieldMap(criteria, EntityOperator.AND);

        final String entityCondWhereString = entityCondition.makeWhereString(modelEntity, params);

        if (entityCondWhereString.length() > 0) {
          updateSql.append(" WHERE ");
          updateSql.append(entityCondWhereString);
        }
      }

      final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
      final String sql = updateSql.toString();

      if (log.isDebugEnabled()) {
        log.debug("Running bulk update SQL: '" + sql + "'");
      }

      processor.prepareStatement(sql);

      for (final EntityConditionParam conditionParam : params) {
        SqlJdbcUtil.setValue(
            processor,
            conditionParam.getModelField(),
            modelEntity.getEntityName(),
            conditionParam.getFieldValue(),
            modelFieldTypeReader);
      }

      try {
        result = processor.executeUpdate();
      } finally {
        processor.close();
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }

    return result;
  }

  public int bulkCopyColumnValuesByAnd(
      final String entityName, final Map updateColumns, final Map criteria) {
    int result = 0;

    if ((entityName == null) || (updateColumns == null) || updateColumns.isEmpty()) {
      return 0;
    }

    try {
      final ModelEntity modelEntity = delegatorInterface.getModelEntity(entityName);

      final GenericHelper entityHelper = delegatorInterface.getEntityHelper(entityName);

      final ModelFieldTypeReader modelFieldTypeReader =
          ModelFieldTypeReader.getModelFieldTypeReader(entityHelper.getHelperName());

      final ArrayList<EntityConditionParam> params = new ArrayList<EntityConditionParam>();

      // generate the update sql
      final StringBuilder updateSql = new StringBuilder("UPDATE ");

      updateSql.append(modelEntity.getTableName(entityHelper.getHelperName()));
      updateSql.append(" SET ");

      if (!modelEntity.areFields(updateColumns.keySet())) {
        throw new GenericModelException(
            "At least one of the passed fields for update is not valid: "
                + updateColumns.keySet().toString());
      }

      if (!modelEntity.areFields(updateColumns.values())) {
        throw new GenericModelException(
            "At least one of the passed fields for update is not valid: "
                + updateColumns.values().toString());
      }

      for (final Iterator iterator = updateColumns.keySet().iterator(); iterator.hasNext(); ) {
        final String column = (String) iterator.next();
        updateSql.append(" ");
        final ModelField toModelField = modelEntity.getField(column);
        updateSql.append(toModelField.getColName());
        updateSql.append(" = ");
        final ModelField fromModelField = modelEntity.getField((String) updateColumns.get(column));
        updateSql.append(fromModelField.getColName());
        if (iterator.hasNext()) {
          updateSql.append(", ");
        }
      }

      if ((criteria != null) && !criteria.isEmpty()) {
        if (!modelEntity.areFields(criteria.keySet())) {
          throw new GenericModelException(
              "At least one of the passed fields is not valid: " + criteria.keySet().toString());
        }

        // generate the where clause
        final EntityFieldMap entityCondition = new EntityFieldMap(criteria, EntityOperator.AND);

        final String entityCondWhereString = entityCondition.makeWhereString(modelEntity, params);

        if (entityCondWhereString.length() > 0) {
          updateSql.append(" WHERE ");
          updateSql.append(entityCondWhereString);
        }
      }

      final SQLProcessor processor = new AutoCommitSQLProcessor(entityHelper.getHelperName());
      final String sql = updateSql.toString();

      if (log.isDebugEnabled()) {
        log.debug("Running bulk update SQL: '" + sql + '\'');
      }

      processor.prepareStatement(sql);

      for (final EntityConditionParam conditionParam : params) {
        SqlJdbcUtil.setValue(
            processor,
            conditionParam.getModelField(),
            modelEntity.getEntityName(),
            conditionParam.getFieldValue(),
            modelFieldTypeReader);
      }

      try {
        result = processor.executeUpdate();
      } finally {
        processor.close();
      }
    } catch (final GenericEntityException e) {
      throw new DataAccessException(e);
    } catch (final NoClassDefFoundError e) {
      // under JDK 1.3 unit tests - javax.sql.XADataSource cannot be found.
      // this shouldn't affect runtime - application servers should ship the jar
    }

    return result;
  }

  @Override
  public ModelReader getModelReader() {
    return delegatorInterface.getModelReader();
  }

  @Override
  public void refreshSequencer() {
    delegatorInterface.refreshSequencer();
  }

  @Override
  public boolean removeRelated(String relationName, GenericValue schemeGv) {
    try {
      return delegatorInterface.removeRelated(relationName, schemeGv) > 0;
    } catch (GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public DelegatorInterface getDelegatorInterface() {
    return delegatorInterface;
  }

  @Override
  public List<GenericValue> transform(
      final String entityName,
      final EntityCondition entityCondition,
      final List<String> orderBy,
      final String lockField,
      final Transformation transformation) {
    try {
      return delegatorInterface.transform(
          entityName, entityCondition, orderBy, lockField, transformation);
    } catch (GenericEntityException e) {
      throw new DataAccessException(e);
    }
  }

  @Override
  public GenericValue transformOne(
      final String entityName,
      final EntityCondition entityCondition,
      final String lockField,
      final Transformation transformation) {
    final List<GenericValue> transformedValues =
        transform(entityName, entityCondition, null, lockField, transformation);
    Validate.validState(
        transformedValues.size() == 1,
        "Expected one match for %s but found %d: %s",
        entityCondition,
        transformedValues.size(),
        transformedValues);
    return transformedValues.get(0);
  }

  /**
   * Class that holds all the information necessary to update a value in a SQLProcessor. Instances
   * of {@link Value} are used to hold field values.
   */
  static final class Updater {
    final ModelFieldTypeReader modelFieldTypeReader;
    final String entityName;

    Updater(
        @Nonnull final ModelFieldTypeReader modelFieldTypeReader,
        @Nonnull final String entityName) {
      this.modelFieldTypeReader = notNull("modelFieldTypeReader", modelFieldTypeReader);
      this.entityName = notNull("entityName", entityName);
    }

    public Value create(final ModelField field, final Object value) {
      return new Value(field, value);
    }

    class Value {
      final ModelField field;
      final Object value;

      Value(final ModelField field, final Object value) {
        this.field = field;
        this.value = value;
      }

      void setValue(final SQLProcessor processor) throws GenericEntityException {
        SqlJdbcUtil.setValue(processor, field, entityName, value, modelFieldTypeReader);
      }
    }
  }

  /**
   * Get the field type given a table and field name. Returns a null function if the table can't be
   * found, and a null type string if the entity can't be found.
   */
  class FieldTypeResolver implements Function<String, Function<String, String>> {
    @Nullable
    public Function<String, String> get(final String entityName) {
      final ModelEntity table = delegatorInterface.getModelEntity(entityName);
      return (table != null) ? new FieldTypeResolverFunction(table) : null;
    }
  }

  static class FieldTypeResolverFunction implements Function<String, String> {
    private final ModelEntity table;

    FieldTypeResolverFunction(ModelEntity table) {
      this.table = table;
    }

    @Nullable
    @Override
    public String get(final String fieldName) {
      final ModelField field = table.getField(fieldName);
      return (field != null) ? field.getType() : null;
    }
  }
}
 /**
  * Make the correct search is performed when the search request does not contain any "updated
  * date" critera and we have determined that they can be included in the comment search.
  *
  * @throws Exception indicates some unexpected failure.
  */
 @Test
 public void testGetRecentCommentsIssuesNoDates() throws Exception {
   final SearchRequest request = new SearchRequest();
   final List<Long> issueIds = CollectionBuilder.newBuilder(5674L).asList();
   _testGetRecentComments(issueIds, request, null, true, createIssueQuery(issueIds));
 }