// Copyright 2017 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.api.ads.adwords.jaxws.utils.v201702; import com.google.api.ads.adwords.jaxws.v201702.cm.DateRange; import com.google.api.ads.adwords.jaxws.v201702.cm.OrderBy; import com.google.api.ads.adwords.jaxws.v201702.cm.Paging; import com.google.api.ads.adwords.jaxws.v201702.cm.Predicate; import com.google.api.ads.adwords.jaxws.v201702.cm.PredicateOperator; import com.google.api.ads.adwords.jaxws.v201702.cm.Selector; import com.google.api.ads.adwords.jaxws.v201702.cm.SortOrder; import com.google.api.ads.adwords.lib.selectorfields.EntityField; import com.google.api.ads.adwords.lib.utils.SelectorBuilderInterface; import com.google.common.collect.Sets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Iterator; import java.util.Set; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.joda.time.DateTime; /** * A builder for {@link Selector} objects. * * This builder is not thread safe. */ class SelectorBuilderImpl implements SelectorBuilderInterface<Selector> { /** * The default date format for the AdWords API */ protected static final String DEFAULT_DATE_FORMAT = "yyyyMMdd"; /** * The default Id property name on all entities */ private static final String ID_PROPERTY = "Id"; private Set<String> fields = Sets.newLinkedHashSet(); private Set<OrderByWrapper> ordering = Sets.newLinkedHashSet(); private Set<Predicate> predicates = Sets.newLinkedHashSet(); private DateRange dateRange; private Paging paging; @Override public Selector build() { Selector selectorCopy = new Selector(); Set<OrderBy> orderingCopy = this.copyOrderingSet(); Set<Predicate> predicatesCopy = this.copyPredicatesSet(); selectorCopy.getFields().addAll(Sets.newLinkedHashSet(this.fields)); selectorCopy.getOrdering().addAll(orderingCopy); selectorCopy.getPredicates().addAll(predicatesCopy); if (this.dateRange != null) { DateRange newDateRange = new DateRange(); newDateRange.setMin(this.dateRange.getMin()); newDateRange.setMax(this.dateRange.getMax()); selectorCopy.setDateRange(newDateRange); } if (this.paging != null) { Paging newPaging = new Paging(); newPaging.setStartIndex(this.paging.getStartIndex()); newPaging.setNumberResults(this.paging.getNumberResults()); selectorCopy.setPaging(newPaging); } return selectorCopy; } /** * Copies the whole set of predicates, by creating new instances of each one in the given set. * * @return the new set of Predicate objects with different instance for each of the Predicate */ private Set<Predicate> copyPredicatesSet() { Set<Predicate> predicatesCopy = Sets.newLinkedHashSet(); for (Predicate predicate : this.predicates) { Predicate copyPredicate = new Predicate(); copyPredicate.setField(predicate.getField()); copyPredicate.setOperator(predicate.getOperator()); copyPredicate.getValues().addAll(predicate.getValues()); predicatesCopy.add(copyPredicate); } return predicatesCopy; } /** * Copies the whole set of OrderBy objects, by creating new instances of each one in the given * set. * * @return the new set of OrderBy objects with different instance for each of the OrderBy */ private Set<OrderBy> copyOrderingSet() { Set<OrderBy> orderingCopy = Sets.newLinkedHashSet(); for (OrderBy order : this.ordering) { OrderBy copyOrder = new OrderBy(); copyOrder.setField(order.getField()); copyOrder.setSortOrder(order.getSortOrder()); orderingCopy.add(copyOrder); } return orderingCopy; } @Override public SelectorBuilderImpl fields(String... fields) { this.fields = Sets.newLinkedHashSet(); Collections.addAll(this.fields, fields); return this; } @Override public SelectorBuilderImpl fields(EntityField... fields) { return fields(this.enumFieldsToNames(fields)); } /** * Returns the array of Strings resulting from calling {@code name()} on each field. * * @param fields the array of fields as Java Enums. */ private String[] enumFieldsToNames(EntityField... fields) { String[] fieldsNames = new String[fields.length]; for (int i = 0; i < fields.length; i++) { fieldsNames[i] = fields[i].name(); } return fieldsNames; } @Override public SelectorBuilderImpl increaseOffsetBy(int additionalOffset) { if (this.paging == null) { this.paging = new Paging(); } Integer startIndex = this.paging.getStartIndex(); if (startIndex == null) { startIndex = 0; } this.paging.setStartIndex(startIndex + additionalOffset); return this; } @Override public SelectorBuilderImpl limit(int limit) { if (this.paging == null) { this.paging = new Paging(); } this.paging.setNumberResults(limit); return this; } @Override public SelectorBuilderImpl offset(int offset) { if (this.paging == null) { this.paging = new Paging(); } this.paging.setStartIndex(offset); return this; } @Override public SelectorBuilderImpl removeLimitAndOffset() { this.paging = null; return this; } @Override public SelectorBuilderImpl orderAscBy(String field) { OrderByWrapper order = new OrderByWrapper(); order.setField(field); order.setSortOrder(SortOrder.ASCENDING); this.ordering.add(order); return this; } @Override public SelectorBuilderImpl orderAscBy(EntityField field) { return this.orderAscBy(field.name()); } @Override public SelectorBuilderImpl orderDescBy(String field) { OrderByWrapper order = new OrderByWrapper(); order.setField(field); order.setSortOrder(SortOrder.DESCENDING); this.ordering.add(order); return this; } @Override public SelectorBuilderImpl orderDescBy(EntityField field) { return this.orderDescBy(field.name()); } @Override public SelectorBuilderImpl removeOrderBy(String field) { Iterator<OrderByWrapper> iterator = this.ordering.iterator(); while (iterator.hasNext()) { OrderByWrapper order = iterator.next(); if (order.getField().equals(field)) { iterator.remove(); } } return this; } @Override public SelectorBuilderImpl removeOrderBy(EntityField field) { return this.removeOrderBy(field.name()); } @Override public SelectorBuilderImpl forDateRange(DateTime start, DateTime end) { if (this.dateRange == null) { this.dateRange = new DateRange(); } DateFormat dateFormat = new SimpleDateFormat(DEFAULT_DATE_FORMAT); if (start != null) { this.dateRange.setMin(dateFormat.format(start.toDate())); } if (end != null) { this.dateRange.setMax(dateFormat.format(end.toDate())); } return this; } @Override public SelectorBuilderImpl equals(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.EQUALS); } @Override public SelectorBuilderImpl equals(EntityField field, String propertyValue) { return this.equals(field.name(), propertyValue); } @Override public SelectorBuilderImpl notEquals(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.NOT_EQUALS); } @Override public SelectorBuilderImpl notEquals(EntityField field, String propertyValue) { return this.notEquals(field.name(), propertyValue); } @Override public SelectorBuilderImpl contains(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.CONTAINS); } @Override public SelectorBuilderImpl contains(EntityField field, String propertyValue) { return this.contains(field.name(), propertyValue); } @Override public SelectorBuilderImpl containsIgnoreCase(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.CONTAINS_IGNORE_CASE); } @Override public SelectorBuilderImpl containsIgnoreCase(EntityField field, String propertyValue) { return this.containsIgnoreCase(field.name(), propertyValue); } @Override public SelectorBuilderImpl doesNotContain(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.DOES_NOT_CONTAIN); } @Override public SelectorBuilderImpl doesNotContain(EntityField field, String propertyValue) { return this.doesNotContain(field.name(), propertyValue); } @Override public SelectorBuilderImpl doesNotContainIgnoreCase(String field, String propertyValue) { return this.singleValuePredicate(field, propertyValue, PredicateOperator.DOES_NOT_CONTAIN_IGNORE_CASE); } @Override public SelectorBuilderImpl doesNotContainIgnoreCase(EntityField field, String propertyValue) { return this.doesNotContainIgnoreCase(field.name(), propertyValue); } @Override public SelectorBuilderImpl greaterThan(String field, long propertyValue) { return this.singleValuePredicate(field, Long.toString(propertyValue), PredicateOperator.GREATER_THAN); } @Override public SelectorBuilderImpl greaterThan(EntityField field, long propertyValue) { return this.greaterThan(field.name(), propertyValue); } @Override public SelectorBuilderImpl greaterThanEquals(String field, long propertyValue) { return this.singleValuePredicate(field, Long.toString(propertyValue), PredicateOperator.GREATER_THAN_EQUALS); } @Override public SelectorBuilderImpl greaterThanEquals(EntityField field, long propertyValue) { return this.greaterThanEquals(field.name(), propertyValue); } @Override public SelectorBuilderImpl lessThan(String field, long propertyValue) { return this.singleValuePredicate(field, Long.toString(propertyValue), PredicateOperator.LESS_THAN); } @Override public SelectorBuilderImpl lessThan(EntityField field, long propertyValue) { return this.lessThan(field.name(), propertyValue); } @Override public SelectorBuilderImpl lessThanEquals(String field, long propertyValue) { return this.singleValuePredicate(field, Long.toString(propertyValue), PredicateOperator.LESS_THAN_EQUALS); } @Override public SelectorBuilderImpl lessThanEquals(EntityField field, long propertyValue) { return this.lessThanEquals(field.name(), propertyValue); } /** * Adds a predicate for the specified field, property value, and operator. */ private SelectorBuilderImpl singleValuePredicate(String field, String propertyValue, PredicateOperator operator) { Predicate predicate = new Predicate(); predicate.setField(field); predicate.setOperator(operator); predicate.getValues().add(propertyValue); this.predicates.add(predicate); return this; } @Override public SelectorBuilderImpl equalsId(Long id) { return this.singleValuePredicate(ID_PROPERTY, id.toString(), PredicateOperator.EQUALS); } @Override public SelectorBuilderImpl in(String field, String... values) { return this.multipleValuePredicate(field, values, PredicateOperator.IN); } @Override public SelectorBuilderImpl in(EntityField field, String... values) { return this.in(field.name(), values); } @Override public SelectorBuilderImpl notIn(String field, String... values) { return this.multipleValuePredicate(field, values, PredicateOperator.NOT_IN); } @Override public SelectorBuilderImpl notIn(EntityField field, String... values) { return this.notIn(field.name(), values); } @Override public SelectorBuilderImpl containsAny(String field, String... values) { return this.multipleValuePredicate(field, values, PredicateOperator.CONTAINS_ANY); } @Override public SelectorBuilderImpl containsAny(EntityField field, String... values) { return this.containsAny(field.name(), values); } @Override public SelectorBuilderImpl containsAll(String field, String... values) { return this.multipleValuePredicate(field, values, PredicateOperator.CONTAINS_ALL); } @Override public SelectorBuilderImpl containsAll(EntityField field, String... values) { return this.containsAll(field.name(), values); } @Override public SelectorBuilderImpl containsNone(String field, String... values) { return this.multipleValuePredicate(field, values, PredicateOperator.CONTAINS_NONE); } @Override public SelectorBuilderImpl containsNone(EntityField field, String... values) { return this.containsNone(field.name(), values); } /** * Adds a predicate for the specified field, property values, and operator. */ private SelectorBuilderImpl multipleValuePredicate(String field, String[] propertyValues, PredicateOperator operator) { if (propertyValues == null) { return this; } Predicate predicate = new Predicate(); predicate.setOperator(operator); predicate.setField(field); for (String propertyValue : propertyValues) { predicate.getValues().add(propertyValue); } this.predicates.add(predicate); return this; } /** * Wrapper that adds equals and hashCode methods to the current implementation of OrderBy. */ private static final class OrderByWrapper extends OrderBy { /** * The {@code equals} method only considers the {@code field} and the {@code sortOrder} * attributes. */ @Override public boolean equals(Object obj) { if (!(obj instanceof OrderBy)) { return false; } OrderBy other = (OrderBy) obj; return new EqualsBuilder().append(getField(), other.getField()) .append(getSortOrder(), other.getSortOrder()).isEquals(); } /** * The {@code hashCode} method only considers the {@code field} and the {@code sortOrder} * attributes. */ @Override public int hashCode() { return new HashCodeBuilder().append(getField()).append(getSortOrder()).toHashCode(); } } }