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()); }
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)); }
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); }
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); } } } } }
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)); }