use of jetbrains.buildServer.server.rest.errors.LocatorProcessException in project teamcity-rest by JetBrains.
the class BranchFinder method getBranchSearchOptions.
@NotNull
private BranchSearchOptions getBranchSearchOptions(@NotNull final Locator locator) {
BranchesPolicy branchesPolicy = BranchesPolicy.ACTIVE_HISTORY_AND_ACTIVE_VCS_BRANCHES;
final String policyDimension = locator.getSingleDimensionValue(POLICY);
if (policyDimension != null) {
try {
branchesPolicy = BranchesPolicy.valueOf(policyDimension.toUpperCase());
} catch (IllegalArgumentException e) {
throw new BadRequestException("Invalid value '" + policyDimension + "' for '" + POLICY + "' dimension. Supported values are: " + Arrays.toString(BranchesPolicy.values()));
}
}
Boolean changesFromDependencies;
try {
changesFromDependencies = locator.getSingleDimensionValueAsStrictBoolean(CHANGES_FROM_DEPENDENCIES, null);
} catch (LocatorProcessException e) {
throw new LocatorProcessException("Invalid '" + CHANGES_FROM_DEPENDENCIES + "' dimension", e);
}
return new BranchSearchOptions(branchesPolicy, changesFromDependencies);
}
use of jetbrains.buildServer.server.rest.errors.LocatorProcessException in project teamcity-rest by JetBrains.
the class Locator method parse.
@NotNull
private static HashMap<String, List<String>> parse(@NotNull final String locator, @Nullable final String[] supportedDimensions, @NotNull final Collection<String> hiddenSupportedDimensions, final boolean extendedMode) {
StringPool stringPool = RestContext.getThreadLocalStringPool();
HashMap<String, List<String>> result = new HashMap<>();
String currentDimensionName;
String currentDimensionValue;
int parsedIndex = 0;
while (parsedIndex < locator.length()) {
// expecting name start at parsedIndex
int nameEnd = locator.length();
String nextDelimeter = null;
int currentIndex = parsedIndex;
while (currentIndex < locator.length()) {
if (locator.startsWith(DIMENSIONS_DELIMITER, currentIndex)) {
nextDelimeter = DIMENSIONS_DELIMITER;
nameEnd = currentIndex;
break;
}
if (locator.startsWith(DIMENSION_COMPLEX_VALUE_START_DELIMITER, currentIndex)) {
nextDelimeter = DIMENSION_COMPLEX_VALUE_START_DELIMITER;
nameEnd = currentIndex;
break;
}
if (locator.startsWith(DIMENSION_NAME_VALUE_DELIMITER, currentIndex)) {
nextDelimeter = DIMENSION_NAME_VALUE_DELIMITER;
nameEnd = currentIndex;
break;
}
currentIndex++;
}
if (nameEnd == parsedIndex) {
throw new LocatorProcessException(locator, parsedIndex, "Could not find dimension name, found '" + nextDelimeter + "' instead");
}
currentDimensionName = locator.substring(parsedIndex, nameEnd);
if (!isValidName(currentDimensionName, supportedDimensions, hiddenSupportedDimensions, extendedMode)) {
throw new LocatorProcessException(locator, parsedIndex, "Invalid dimension name :'" + currentDimensionName + "'. Should contain only alpha-numeric symbols" + (supportedDimensions == null || supportedDimensions.length == 0 ? "" : " or be known one: " + Arrays.toString(supportedDimensions)));
}
currentDimensionValue = "";
parsedIndex = nameEnd;
if (nextDelimeter != null) {
if (DIMENSIONS_DELIMITER.equals(nextDelimeter)) {
parsedIndex = nameEnd + nextDelimeter.length();
} else {
if (DIMENSION_NAME_VALUE_DELIMITER.equals(nextDelimeter)) {
parsedIndex = nameEnd + nextDelimeter.length();
}
if (DIMENSION_COMPLEX_VALUE_START_DELIMITER.equals(nextDelimeter)) {
parsedIndex = nameEnd;
}
// here begins the value at parsedIndex
final String valueAndRest = locator.substring(parsedIndex);
if (valueAndRest.startsWith(DIMENSION_COMPLEX_VALUE_START_DELIMITER)) {
// complex value detected
final int complexValueEnd = findNextOrEndOfStringConsideringBraces(valueAndRest, null);
if (complexValueEnd < 0) {
throw new LocatorProcessException(locator, parsedIndex + DIMENSION_COMPLEX_VALUE_START_DELIMITER.length(), "Could not find matching '" + DIMENSION_COMPLEX_VALUE_END_DELIMITER + "'");
}
currentDimensionValue = valueAndRest.substring(DIMENSION_COMPLEX_VALUE_START_DELIMITER.length(), complexValueEnd - DIMENSION_COMPLEX_VALUE_END_DELIMITER.length());
parsedIndex = parsedIndex + complexValueEnd;
if (parsedIndex != locator.length()) {
if (!locator.startsWith(DIMENSIONS_DELIMITER, parsedIndex)) {
throw new LocatorProcessException(locator, parsedIndex, "No dimensions delimiter '" + DIMENSIONS_DELIMITER + "' after complex value");
} else {
parsedIndex += DIMENSIONS_DELIMITER.length();
}
}
} else {
int valueEnd = findNextOrEndOfStringConsideringBraces(valueAndRest, DIMENSIONS_DELIMITER);
if (valueEnd < 0) {
throw new LocatorProcessException(locator, parsedIndex, "Could not find matching '" + DIMENSION_COMPLEX_VALUE_END_DELIMITER + "'");
} else if (valueEnd == valueAndRest.length()) {
currentDimensionValue = valueAndRest;
parsedIndex = locator.length();
} else {
currentDimensionValue = valueAndRest.substring(0, valueEnd);
parsedIndex = parsedIndex + valueEnd + DIMENSIONS_DELIMITER.length();
}
if (ANY_LITERAL.equals(currentDimensionValue)) {
// this was not a complex value, so setting exactly the same string to be able to determine this on retrieving
currentDimensionValue = ANY_LITERAL;
}
}
String unescapedValue = getBase64UnescapedSingleValue(currentDimensionValue, extendedMode);
if (unescapedValue != null)
currentDimensionValue = unescapedValue;
}
}
currentDimensionName = stringPool.reuse(currentDimensionName);
final List<String> currentList = result.get(currentDimensionName);
final List<String> newList;
if (currentList == null) {
// Dimension with an empy string value is a frequent case in a Fields, so let's reuse a special list for that list.
newList = currentDimensionValue.equals("") ? LIST_WITH_EMPTY_STRING : Arrays.asList(currentDimensionValue);
} else {
newList = new ArrayList<>(currentList);
newList.add(stringPool.reuse(currentDimensionValue));
}
result.put(currentDimensionName, newList);
}
return result;
}
use of jetbrains.buildServer.server.rest.errors.LocatorProcessException in project teamcity-rest by JetBrains.
the class GenericBuildsFilter method isIncluded.
public boolean isIncluded(@NotNull final SBuild build) {
if (myAgentName != null && !myAgentName.equals(build.getAgentName())) {
return false;
}
if (myBuildType != null && !myBuildType.getBuildTypeId().equals(build.getBuildTypeId())) {
return false;
}
if (myProject != null && !isUnderProject(myProject, build)) {
return false;
}
if (myStatus != null && !myStatus.equalsIgnoreCase(build.getStatusDescriptor().getStatus().getText())) {
return false;
}
if (myNumber != null && !myNumber.equals(build.getBuildNumber())) {
return false;
}
if (!FilterUtil.isIncludedByBooleanFilter(myPersonal, build.isPersonal())) {
return false;
}
if (!FilterUtil.isIncludedByBooleanFilter(myCanceled, build.getCanceledInfo() != null)) {
return false;
}
if (!FilterUtil.isIncludedByBooleanFilter(myRunning, !build.isFinished())) {
return false;
}
if (!FilterUtil.isIncludedByBooleanFilter(myPinned, build.isPinned())) {
return false;
}
if (myTags != null && myTags.size() > 0 && myTags.get(0).startsWith("format:extended")) {
@NotNull final List<String> buildTags = build.getTags();
// unofficial experimental support for "tag:(format:regexp,value:.*)" tag specification
// todo: locator parsing logic should be moved to build locator parsing
final Locator tagsLocator;
try {
tagsLocator = new Locator(myTags.get(0));
if (!isTagsMatchLocator(buildTags, tagsLocator)) {
return false;
}
final Set<String> unusedDimensions = tagsLocator.getUnusedDimensions();
if (unusedDimensions.size() > 0) {
throw new BadRequestException("Unknown dimensions in locator 'tag': " + unusedDimensions);
}
} catch (LocatorProcessException e) {
throw new BadRequestException("Invalid locator 'tag': " + e.getMessage(), e);
}
} else if (myTags != null && myTags.size() > 0 && !build.getTags().containsAll(myTags)) {
return false;
}
if (!myBranchMatcher.matches(build.getBuildPromotion())) {
return false;
} else {
// default to only default branch
if (!myBranchMatcher.isDefined()) {
@Nullable final Branch buildBranch = build.getBuildPromotion().getBranch();
if (buildBranch != null && !buildBranch.isDefaultBranch())
return false;
}
}
if (myUser != null) {
final SUser userWhoTriggered = build.getTriggeredBy().getUser();
if (!build.getTriggeredBy().isTriggeredByUser() || (userWhoTriggered == null) || (myUser.getId() != userWhoTriggered.getId())) {
return false;
}
}
if (isExcludedBySince(build))
return false;
if (myUntil != null) {
if (myUntil.before(build)) {
return false;
}
}
if (myAgents != null && !myAgents.contains(build.getAgent())) {
return false;
}
if (myParameterCondition != null) {
if (!myParameterCondition.matches(Build.getBuildResultingParameters(build.getBuildPromotion(), myServiceLocator))) {
return false;
}
}
return true;
}
use of jetbrains.buildServer.server.rest.errors.LocatorProcessException in project teamcity-rest by JetBrains.
the class FinderImpl method getItemsByLocator.
@NotNull
private PagedSearchResult<ITEM> getItemsByLocator(@Nullable final Locator originalLocator, final boolean multipleItemsQuery) {
long startTime = System.nanoTime();
Locator locator;
if (originalLocator == null) {
// go on with empty locator
locator = createLocator(null, Locator.createEmptyLocator());
} else {
locator = originalLocator;
locator.processHelpRequest();
}
String contextItemText = locator.getSingleDimensionValue(CONTEXT_ITEM_DIMENSION_NAME);
if (contextItemText != null) {
List<ITEM> contextObjects = getContextItems(contextItemText);
if (contextObjects == null)
throw new BadRequestException("Context variable '" + contextItemText + "' is used in locator, but is not present in the context");
if (contextObjects.isEmpty())
throw new BadRequestException("Context variable '" + contextItemText + "' is used in locator, but the list does not contain any elements");
// so far do not support additional filtering or other dimensions if context item is used
locator.checkLocatorFullyProcessed();
return new PagedSearchResult<>(contextObjects, null, null);
}
if (!locator.isEmpty()) {
final ITEM singleItem;
try {
singleItem = myDataBinding.findSingleItem(locator);
} catch (NotFoundException e) {
if (multipleItemsQuery && !isReportErrorOnNothingFound(locator)) {
// returning empty collection for multiple items query
return new PagedSearchResult<>(Collections.emptyList(), null, null);
}
throw e;
}
if (singleItem != null) {
final Set<String> singleItemUsedDimensions = locator.getUsedDimensions();
// ignore start:0 dimension
final Long startDimension = locator.getSingleDimensionValueAsLong(PagerData.START);
if (startDimension == null || startDimension != 0) {
locator.markUnused(PagerData.START);
}
ItemFilter<ITEM> filter;
try {
filter = getDataBindingWithLogicOpsSupport(locator, myDataBinding).getFilter();
} catch (NotFoundException e) {
throw new NotFoundException("Invalid filter for found single item, try omitting extra dimensions: " + e.getMessage(), e);
} catch (BadRequestException e) {
throw new BadRequestException("Invalid filter for found single item, try omitting extra dimensions: " + e.getMessage(), e);
} catch (Exception e) {
throw new BadRequestException("Invalid filter for found single item, try omitting extra dimensions: " + e.toString(), e);
}
// mark as used as it has no influence on single item
locator.markUsed(DIMENSION_UNIQUE);
// checking before invoking filter to report any unused dimensions before possible error reporting in filter
locator.checkLocatorFullyProcessed();
if (!filter.isIncluded(singleItem)) {
final String message = "Found single item by " + StringUtil.pluralize("dimension", singleItemUsedDimensions.size()) + " " + singleItemUsedDimensions + ", but that was filtered out using the entire locator '" + locator + "'";
if (multipleItemsQuery && !isReportErrorOnNothingFound(locator)) {
LOG.debug(message);
return new PagedSearchResult<>(Collections.emptyList(), null, null);
} else {
throw new NotFoundException(message);
}
}
return new PagedSearchResult<>(Collections.singletonList(singleItem), null, null);
}
// nothing found - no dimensions should be marked as used then
locator.markAllUnused();
}
FinderDataBinding.ItemHolder<ITEM> unfilteredItems;
PagingItemFilter<ITEM> pagingFilter;
try {
FinderDataBinding.LocatorDataBinding<ITEM> locatorDataBinding = getDataBindingWithLogicOpsSupport(locator, myDataBinding);
unfilteredItems = locatorDataBinding.getPrefilteredItems();
DuplicateChecker<ITEM> duplicateChecker = myDataBinding.createDuplicateChecker();
if (duplicateChecker != null) {
// get the dimension only for supporting finders so that unused dimension is reported otherwise
boolean deduplicate = locator.getSingleDimensionValueAsStrictBoolean(DIMENSION_UNIQUE, locator.isAnyPresent(DIMENSION_ITEM));
if (deduplicate) {
unfilteredItems = new DeduplicatingItemHolder<>(unfilteredItems, duplicateChecker);
}
}
pagingFilter = getPagingFilter(locator, locatorDataBinding.getFilter());
} catch (LocatorProcessException | BadRequestException | IllegalArgumentException e) {
if (!locator.isHelpRequested()) {
throw e;
}
throw new BadRequestException(e.getMessage() + "\nLocator details: " + locator.getLocatorDescription(locator.helpOptions().getSingleDimensionValueAsStrictBoolean("hidden", false)), e);
}
locator.checkLocatorFullyProcessed();
return getItems(pagingFilter, unfilteredItems, locator, startTime);
}
use of jetbrains.buildServer.server.rest.errors.LocatorProcessException in project teamcity-rest by JetBrains.
the class FinderImpl method getFilter.
@NotNull
@Override
public ItemFilter<ITEM> getFilter(@NotNull final String locatorText) {
final Locator locator = createLocator(locatorText, null);
final ItemFilter<ITEM> result;
try {
result = getFilterWithLogicOpsSupport(locator, myDataBinding.getLocatorDataBinding(locator));
} catch (LocatorProcessException | BadRequestException e) {
if (!locator.isHelpRequested()) {
throw e;
}
throw new BadRequestException(e.getMessage() + "\nLocator details: " + locator.getLocatorDescription(locator.helpOptions().getSingleDimensionValueAsStrictBoolean("hidden", false)), e);
}
locator.checkLocatorFullyProcessed();
return result;
}
Aggregations