Share your feedback about the Google Ads (AdWords) API. Take the 2021 AdWords API and Google Ads API Annual Survey.

The AdWords API will sunset on April 27, 2022. Migrate to the Google Ads API to take advantage of the latest Google Ads features.

Advanced Operations Samples

The code samples below provide examples of common advanced operations using the AdWords API. Client Library.

Add an ad customizer feed

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdCustomizerFeed;
import com.google.api.ads.adwords.axis.v201809.cm.AdCustomizerFeedAttribute;
import com.google.api.ads.adwords.axis.v201809.cm.AdCustomizerFeedAttributeType;
import com.google.api.ads.adwords.axis.v201809.cm.AdCustomizerFeedOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdCustomizerFeedServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.ExpandedTextAd;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItem;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemAdGroupTarget;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemAttributeValue;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemOperation;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemTargetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemTargetReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemTargetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.joda.time.DateTime;

/**
 * This example adds an ad customizer feed and associates it with the customer. Then it adds an ad
 * that uses the feed to populate dynamic data.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class AddAdCustomizer {

  private static class AddAdCustomizerParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private List<Long> adGroupIds = new ArrayList<>();

    @Parameter(names = ArgumentNames.FEED_NAME, required = true)
    private String feedName;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddAdCustomizerParams params = new AddAdCustomizerParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupIds = Arrays.asList(
          Long.valueOf("INSERT_AD_GROUP_ID_HERE"),
          Long.valueOf("INSERT_AD_GROUP_ID_HERE"));
      params.feedName = "INSERT_FEED_NAME_HERE";
    }

    try {
      runExample(adWordsServices, session, params.adGroupIds, params.feedName);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupIds IDs of the ad groups for which ad customizers will be created.
   * @param feedName the name of the ad customizer feed to create.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session,
      List<Long> adGroupIds, String feedName) throws RemoteException {
    // Create a customizer feed. One feed per account can be used for all ads.
    AdCustomizerFeed adCustomizerFeed = createCustomizerFeed(adWordsServices, session, feedName);

    // Add feed items containing the values we'd like to place in ads.
    createCustomizerFeedItems(adWordsServices, session, adGroupIds, adCustomizerFeed);

    // All set! We can now create ads with customizations.
    createAdsWithCustomizations(adWordsServices, session, adGroupIds, feedName);
  }

  /**
   * Creates a new AdCustomizerFeed.
   *
   * @param feedName the name of the new AdCustomizerFeed
   * @return The new AdCustomizerFeed
   */
  private static AdCustomizerFeed createCustomizerFeed(AdWordsServicesInterface adWordsServices,
      AdWordsSession session, String feedName) throws RemoteException {
    // Get the AdCustomizerFeedService.
    AdCustomizerFeedServiceInterface adCustomizerFeedService =
        adWordsServices.get(session, AdCustomizerFeedServiceInterface.class);
    AdCustomizerFeed customizerFeed = new AdCustomizerFeed();
    customizerFeed.setFeedName(feedName);

    AdCustomizerFeedAttribute nameAttribute = new AdCustomizerFeedAttribute();
    nameAttribute.setName("Name");
    nameAttribute.setType(AdCustomizerFeedAttributeType.STRING);

    AdCustomizerFeedAttribute priceAttribute = new AdCustomizerFeedAttribute();
    priceAttribute.setName("Price");
    priceAttribute.setType(AdCustomizerFeedAttributeType.STRING);

    AdCustomizerFeedAttribute dateAttribute = new AdCustomizerFeedAttribute();
    dateAttribute.setName("Date");
    dateAttribute.setType(AdCustomizerFeedAttributeType.DATE_TIME);

    customizerFeed.setFeedAttributes(
        new AdCustomizerFeedAttribute[] {nameAttribute, priceAttribute, dateAttribute});

    AdCustomizerFeedOperation feedOperation = new AdCustomizerFeedOperation();
    feedOperation.setOperand(customizerFeed);
    feedOperation.setOperator(Operator.ADD);

    AdCustomizerFeed addedFeed = adCustomizerFeedService.mutate(
        new AdCustomizerFeedOperation[] {feedOperation}).getValue()[0];

    System.out.printf(
        "Created ad customizer feed with ID %d, name '%s' and attributes:%n",
        addedFeed.getFeedId(), addedFeed.getFeedName());
    for (AdCustomizerFeedAttribute feedAttribute : addedFeed.getFeedAttributes()) {
      System.out.printf(
          "  ID: %d, name: '%s', type: %s%n",
          feedAttribute.getId(), feedAttribute.getName(), feedAttribute.getType());
    }
    return addedFeed;
  }

  /**
   * Creates FeedItems with the values to use in ad customizations for each ad group in
   * <code>adGroupIds</code>.
   */
  private static void createCustomizerFeedItems(AdWordsServicesInterface adWordsServices,
      AdWordsSession session, List<Long> adGroupIds, AdCustomizerFeed adCustomizerFeed)
      throws RemoteException {
    // Get the FeedItemService.
    FeedItemServiceInterface feedItemService =
        adWordsServices.get(session, FeedItemServiceInterface.class);

    List<FeedItemOperation> feedItemOperations = new ArrayList<>();

    DateTime now = DateTime.now();

    DateTime marsDate = new DateTime(now.getYear(), now.getMonthOfYear(), 1, 0, 0);
    feedItemOperations.add(
        createFeedItemAddOperation(
            "Mars", "$1234.56", marsDate.toString("yyyyMMdd HHmmss"), adCustomizerFeed));

    DateTime venusDate = new DateTime(now.getYear(), now.getMonthOfYear(), 15, 0, 0);
    feedItemOperations.add(
        createFeedItemAddOperation(
            "Venus", "$1450.00", venusDate.toString("yyyyMMdd HHmmss"), adCustomizerFeed));

    FeedItemReturnValue feedItemReturnValue = feedItemService.mutate(
        feedItemOperations.toArray(new FeedItemOperation[feedItemOperations.size()]));

    for (FeedItem addedFeedItem : feedItemReturnValue.getValue()) {
      System.out.printf("Added feed item with ID %d.%n", addedFeedItem.getFeedItemId());
    }

    // Add feed item targeting to restrict the feed item to specific ad groups.
    restrictFeedItemToAdGroup(
        adWordsServices, session, feedItemReturnValue.getValue(0), adGroupIds.get(0));
    restrictFeedItemToAdGroup(
        adWordsServices, session, feedItemReturnValue.getValue(1), adGroupIds.get(1));
  }

  /**
   * Creates a FeedItemOperation that will create a FeedItem with the specified values and ad group
   * target when sent to FeedItemService.mutate.
   *
   * @param name the value for the name attribute of the FeedItem
   * @param price the value for the price attribute of the FeedItem
   * @param date the value for the date attribute of the FeedItem
   * @param adCustomizerFeed the customizer feed
   * @return a new FeedItemOperation for adding a FeedItem
   */
  private static FeedItemOperation createFeedItemAddOperation(
      String name, String price, String date, AdCustomizerFeed adCustomizerFeed) {
    FeedItem feedItem = new FeedItem();
    feedItem.setFeedId(adCustomizerFeed.getFeedId());

    List<FeedItemAttributeValue> attributeValues = new ArrayList<>();

    // FeedAttributes appear in the same order as they were created - Name, Price, Date.
    // See the createCustomizerFeed method for details.
    FeedItemAttributeValue nameAttributeValue = new FeedItemAttributeValue();
    nameAttributeValue.setFeedAttributeId(adCustomizerFeed.getFeedAttributes(0).getId());
    nameAttributeValue.setStringValue(name);
    attributeValues.add(nameAttributeValue);

    FeedItemAttributeValue priceAttributeValue = new FeedItemAttributeValue();
    priceAttributeValue.setFeedAttributeId(adCustomizerFeed.getFeedAttributes(1).getId());
    priceAttributeValue.setStringValue(price);
    attributeValues.add(priceAttributeValue);

    FeedItemAttributeValue dateAttributeValue = new FeedItemAttributeValue();
    dateAttributeValue.setFeedAttributeId(adCustomizerFeed.getFeedAttributes(2).getId());
    dateAttributeValue.setStringValue(date);
    attributeValues.add(dateAttributeValue);

    feedItem.setAttributeValues(
        attributeValues.toArray(new FeedItemAttributeValue[attributeValues.size()]));

    FeedItemOperation feedItemOperation = new FeedItemOperation();
    feedItemOperation.setOperand(feedItem);
    feedItemOperation.setOperator(Operator.ADD);

    return feedItemOperation;
  }

  /** Restricts the feed item to an ad group. */
  private static void restrictFeedItemToAdGroup(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      FeedItem feedItem,
      long adGroupId)
      throws RemoteException {
    // Get the FeedItemTargetingService.
    FeedItemTargetServiceInterface feedItemTargetService =
        adWordsServices.get(session, FeedItemTargetServiceInterface.class);
    FeedItemAdGroupTarget adGroupTarget = new FeedItemAdGroupTarget();
    adGroupTarget.setFeedId(feedItem.getFeedId());
    adGroupTarget.setFeedItemId(feedItem.getFeedItemId());
    adGroupTarget.setAdGroupId(adGroupId);

    FeedItemTargetOperation operation = new FeedItemTargetOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(adGroupTarget);

    FeedItemTargetReturnValue returnValue =
        feedItemTargetService.mutate(new FeedItemTargetOperation[] {operation});
    FeedItemAdGroupTarget addedAdGroupTarget = (FeedItemAdGroupTarget) returnValue.getValue(0);
    System.out.printf(
        "Feed item target for feed ID %d and feed item ID %d "
            + "was created to restrict serving to ad group ID %d.%n",
        addedAdGroupTarget.getFeedId(),
        addedAdGroupTarget.getFeedItemId(),
        addedAdGroupTarget.getAdGroupId());
  }

  /**
   * Creates expanded text ads that use ad customizations for the specified ad group IDs.
   */
  private static void createAdsWithCustomizations(AdWordsServicesInterface adWordsServices,
      AdWordsSession session, List<Long> adGroupIds, String feedName) throws RemoteException {
    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    ExpandedTextAd textAd = new ExpandedTextAd();
    textAd.setHeadlinePart1(String.format("Luxury Cruise to {=%s.Name}", feedName));
    textAd.setHeadlinePart2(String.format("Only {=%s.Price}", feedName));
    textAd.setDescription(String.format("Offer ends in {=countdown(%s.Date)}!", feedName));
    textAd.setFinalUrls(new String[] {"http://www.example.com"});

    // We add the same ad to both ad groups. When they serve, they will show different values, since
    // they match different feed items.
    List<AdGroupAdOperation> adGroupAdOperations = new ArrayList<>();
    for (Long adGroupId : adGroupIds) {
      AdGroupAd adGroupAd = new AdGroupAd();
      adGroupAd.setAdGroupId(adGroupId);
      adGroupAd.setAd(textAd);

      AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation();
      adGroupAdOperation.setOperand(adGroupAd);
      adGroupAdOperation.setOperator(Operator.ADD);

      adGroupAdOperations.add(adGroupAdOperation);
    }

    AdGroupAdReturnValue adGroupAdReturnValue = adGroupAdService.mutate(
        adGroupAdOperations.toArray(new AdGroupAdOperation[adGroupAdOperations.size()]));

    for (AdGroupAd addedAd : adGroupAdReturnValue.getValue()) {
      System.out.printf("Created an ad with ID %d, type '%s' and status '%s'.%n",
          addedAd.getAd().getId(), addedAd.getAd().getAdType(), addedAd.getStatus());
    }
  }
}

Add an ad group level bid modifier

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifier;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifierOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifierReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifierServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.Platform;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;

/**
 * This example illustrates how to add ad group level mobile bid modifier override for a campaign.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class AddAdGroupBidModifier {

  private static final double BID_MODIFIER = 1.5;

  private static class AddAdGroupBidModifierParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddAdGroupBidModifierParams params = new AddAdGroupBidModifierParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where bid modifiers will be added.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session,
      Long adGroupId) throws RemoteException {
    // Get the AdGroupBidModifierService.
    AdGroupBidModifierServiceInterface adGroupBidModifierService =
        adWordsServices.get(session, AdGroupBidModifierServiceInterface.class);

    // Create mobile platform. The ID can be found in the documentation.
    // https://developers.google.com/adwords/api/docs/appendix/platforms
    Platform mobile = new Platform();
    mobile.setId(30001L);

    AdGroupBidModifier adGroupBidModifier = new AdGroupBidModifier();
    adGroupBidModifier.setAdGroupId(adGroupId);
    adGroupBidModifier.setBidModifier(BID_MODIFIER);
    adGroupBidModifier.setCriterion(mobile);

    // Create ADD operation.
    AdGroupBidModifierOperation operation = new AdGroupBidModifierOperation();
    operation.setOperand(adGroupBidModifier);
    // Use 'ADD' to add a new modifier and 'SET' to update an existing one. A
    // modifier can be removed with the 'REMOVE' operator.
    operation.setOperator(Operator.ADD);

    // Update ad group bid modifier.
    AdGroupBidModifierReturnValue result =
        adGroupBidModifierService.mutate(new AdGroupBidModifierOperation[] {operation});
    for (AdGroupBidModifier bidModifierResult : result.getValue()) {
      System.out.printf(
          "Campaign ID %d, ad group ID %d was updated with ad group level modifier: %.4f%n",
          bidModifierResult.getCampaignId(), bidModifierResult.getAdGroupId(),
          bidModifierResult.getBidModifier());
    }
  }
}

Add a page feed specifying URLs for a DSA campaign

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.utils.v201809.SelectorBuilder;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.AttributeFieldMapping;
import com.google.api.ads.adwords.axis.v201809.cm.BiddableAdGroupCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration;
import com.google.api.ads.adwords.axis.v201809.cm.Bids;
import com.google.api.ads.adwords.axis.v201809.cm.Campaign;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignPage;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CpcBid;
import com.google.api.ads.adwords.axis.v201809.cm.DynamicSearchAdsSetting;
import com.google.api.ads.adwords.axis.v201809.cm.Feed;
import com.google.api.ads.adwords.axis.v201809.cm.FeedAttribute;
import com.google.api.ads.adwords.axis.v201809.cm.FeedAttributeType;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItem;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemAttributeValue;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemOperation;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.FeedItemServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.FeedMapping;
import com.google.api.ads.adwords.axis.v201809.cm.FeedMappingOperation;
import com.google.api.ads.adwords.axis.v201809.cm.FeedMappingServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.FeedOperation;
import com.google.api.ads.adwords.axis.v201809.cm.FeedOrigin;
import com.google.api.ads.adwords.axis.v201809.cm.FeedServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Money;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.PageFeed;
import com.google.api.ads.adwords.axis.v201809.cm.Selector;
import com.google.api.ads.adwords.axis.v201809.cm.Webpage;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageCondition;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageConditionOperand;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageParameter;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.selectorfields.v201809.cm.CampaignField;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import java.util.Arrays;

/**
 * This code example adds a page feed to specify precisely which URLs to use with your Dynamic
 * Search Ads campaign. To create a Dynamic Search Ads campaign, run
 * AddDynamicSearchAdsCampaign.java. To get campaigns, run GetCampaigns.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddDynamicPageFeed {

  // The criterion type to be used for DSA page feeds. DSA page feeds use criterionType field
  // instead of the placeholderType field unlike most other feed types.
  private static final int DSA_PAGE_FEED_CRITERION_TYPE = 61;

  // ID that corresponds to the page URLs.
  private static final int DSA_PAGE_URLS_FIELD_ID = 1;

  // ID that corresponds to the labels.
  private static final int DSA_LABEL_FIELD_ID = 2;

  /** Class to keep track of DSA page feed details. */
  private static class DSAFeedDetails {
    private Long feedId;
    private Long urlAttributeId;
    private Long labelAttributeId;
  }

  private static class AddDynamicPageFeedParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true)
    private Long campaignId;

    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddDynamicPageFeedParams params = new AddDynamicPageFeedParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID_HERE");
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.campaignId, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param campaignId the ID of the campaign where the dynamic page feed will be added.
   * @param adGroupId the ID of the ad group where web page targeting will be added.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      Long campaignId,
      Long adGroupId)
      throws RemoteException {
    String dsaPageUrlLabel = "discounts";

    // Get the page feed details. This code example creates a new feed, but you can
    // fetch and re-use an existing feed.
    DSAFeedDetails feedDetails = createFeed(adWordsServices, session);
    createFeedMapping(adWordsServices, session, feedDetails);
    createFeedItems(adWordsServices, session, feedDetails, dsaPageUrlLabel);

    // Associate the page feed with the campaign.
    updateCampaignDsaSetting(adWordsServices, session, campaignId, feedDetails);

    // Optional: Target web pages matching the feed's label in the ad group.
    addDsaTargeting(adWordsServices, session, adGroupId, dsaPageUrlLabel);

    System.out.printf("Dynamic page feed setup is complete for campaign ID %s.%n", campaignId);
  }

  /** Creates the feed for DSA page URLs. */
  private static DSAFeedDetails createFeed(
      AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws ApiException, RemoteException {
    // Get the FeedService.
    FeedServiceInterface feedService = adWordsServices.get(session, FeedServiceInterface.class);

    // Create attributes.
    FeedAttribute urlAttribute = new FeedAttribute();
    urlAttribute.setType(FeedAttributeType.URL_LIST);
    urlAttribute.setName("Page URL");

    FeedAttribute labelAttribute = new FeedAttribute();
    labelAttribute.setType(FeedAttributeType.STRING_LIST);
    labelAttribute.setName("Label");

    // Create the feed.
    Feed dsaPageFeed = new Feed();
    dsaPageFeed.setName("DSA Feed #" + System.currentTimeMillis());
    dsaPageFeed.setAttributes(new FeedAttribute[] {urlAttribute, labelAttribute});
    dsaPageFeed.setOrigin(FeedOrigin.USER);

    // Create operation.
    FeedOperation operation = new FeedOperation();
    operation.setOperand(dsaPageFeed);
    operation.setOperator(Operator.ADD);

    // Add the feed.
    Feed newFeed = feedService.mutate(new FeedOperation[] {operation}).getValue(0);

    DSAFeedDetails feedDetails = new DSAFeedDetails();
    feedDetails.feedId = newFeed.getId();
    FeedAttribute[] savedAttributes = newFeed.getAttributes();
    feedDetails.urlAttributeId = savedAttributes[0].getId();
    feedDetails.labelAttributeId = savedAttributes[1].getId();
    System.out.printf(
        "Feed with name '%s' and ID %d with urlAttributeId %d"
            + " and labelAttributeId %d was created.%n",
        newFeed.getName(),
        feedDetails.feedId,
        feedDetails.urlAttributeId,
        feedDetails.labelAttributeId);
    return feedDetails;
  }

  /** Creates the feed mapping for the DSA page feeds. */
  private static void createFeedMapping(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, DSAFeedDetails feedDetails)
      throws RemoteException {
    // Get the FeedMappingService.
    FeedMappingServiceInterface feedMappingService =
        adWordsServices.get(session, FeedMappingServiceInterface.class);

    // Map the FeedAttributeIds to the fieldId constants.
    AttributeFieldMapping urlFieldMapping = new AttributeFieldMapping();
    urlFieldMapping.setFeedAttributeId(feedDetails.urlAttributeId);
    urlFieldMapping.setFieldId(DSA_PAGE_URLS_FIELD_ID);
    AttributeFieldMapping labelFieldMapping = new AttributeFieldMapping();
    labelFieldMapping.setFeedAttributeId(feedDetails.labelAttributeId);
    labelFieldMapping.setFieldId(DSA_LABEL_FIELD_ID);

    // Create the FeedMapping and operation.
    FeedMapping feedMapping = new FeedMapping();
    feedMapping.setCriterionType(DSA_PAGE_FEED_CRITERION_TYPE);
    feedMapping.setFeedId(feedDetails.feedId);
    feedMapping.setAttributeFieldMappings(
        new AttributeFieldMapping[] {urlFieldMapping, labelFieldMapping});
    FeedMappingOperation operation = new FeedMappingOperation();
    operation.setOperand(feedMapping);
    operation.setOperator(Operator.ADD);

    // Add the field mapping.
    FeedMapping newFeedMapping =
        feedMappingService.mutate(new FeedMappingOperation[] {operation}).getValue(0);
    System.out.printf(
        "Feed mapping with ID %d and criterionType %d was saved for feed with ID %d.%n",
        newFeedMapping.getFeedMappingId(),
        newFeedMapping.getCriterionType(),
        newFeedMapping.getFeedId());
  }

  /** Creates the page URLs in the DSA page feed. */
  private static void createFeedItems(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      DSAFeedDetails feedDetails,
      String labelName)
      throws RemoteException {
    // Get the FeedItemService.
    FeedItemServiceInterface feedItemService =
        adWordsServices.get(session, FeedItemServiceInterface.class);

    // Create operations to add FeedItems.
    FeedItemOperation[] operations =
        new FeedItemOperation[] {
          createDsaUrlAddOperation(
              feedDetails, "http://www.example.com/discounts/rental-cars", labelName),
          createDsaUrlAddOperation(
              feedDetails, "http://www.example.com/discounts/hotel-deals", labelName),
          createDsaUrlAddOperation(
              feedDetails, "http://www.example.com/discounts/flight-deals", labelName),
        };

    FeedItemReturnValue result = feedItemService.mutate(operations);
    for (FeedItem item : result.getValue()) {
      System.out.printf("Feed item with feed item ID %d was added.%n", item.getFeedItemId());
    }
  }

  /** Creates a {@link FeedItemOperation} to add the DSA URL. */
  private static FeedItemOperation createDsaUrlAddOperation(
      DSAFeedDetails feedDetails, String url, String labelName) {
    // Create the FeedItemAttributeValues for the URL and label.
    FeedItemAttributeValue urlAttributeValue = new FeedItemAttributeValue();
    urlAttributeValue.setFeedAttributeId(feedDetails.urlAttributeId);
    // See https://support.google.com/adwords/answer/7166527 for page feed URL recommendations and
    // rules.
    urlAttributeValue.setStringValues(new String[] {url});

    FeedItemAttributeValue labelAttributeValue = new FeedItemAttributeValue();
    labelAttributeValue.setFeedAttributeId(feedDetails.labelAttributeId);
    labelAttributeValue.setStringValues(new String[] {labelName});

    // Create the feed item and operation.
    FeedItem feedItem = new FeedItem();
    feedItem.setFeedId(feedDetails.feedId);

    feedItem.setAttributeValues(
        new FeedItemAttributeValue[] {urlAttributeValue, labelAttributeValue});

    FeedItemOperation operation = new FeedItemOperation();
    operation.setOperand(feedItem);
    operation.setOperator(Operator.ADD);

    return operation;
  }

  /** Updates the campaign DSA setting to add DSA pagefeeds. */
  private static void updateCampaignDsaSetting(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      Long campaignId,
      DSAFeedDetails feedDetails)
      throws ApiException, RemoteException {
    // Get the CampaignService.
    CampaignServiceInterface campaignService =
        adWordsServices.get(session, CampaignServiceInterface.class);

    Selector selector =
        new SelectorBuilder()
            .fields(CampaignField.Id, CampaignField.Settings)
            .equalsId(campaignId)
            .build();

    CampaignPage campaignPage = campaignService.get(selector);
    if (campaignPage.getEntries() == null || campaignPage.getTotalNumEntries() == 0) {
      throw new IllegalArgumentException("No campaign found with ID: " + campaignId);
    }
    Campaign campaign = campaignPage.getEntries(0);

    if (campaign.getSettings() == null) {
      throw new IllegalArgumentException(
          "Campaign with ID " + campaignId + " is not a DSA campaign.");
    }

    DynamicSearchAdsSetting dsaSetting =
        (DynamicSearchAdsSetting)
            Arrays.stream(campaign.getSettings())
                .filter(DynamicSearchAdsSetting.class::isInstance)
                .findFirst()
                .orElse(null);

    if (dsaSetting == null) {
      throw new IllegalArgumentException(
          "Campaign with ID " + campaignId + " is not a DSA campaign.");
    }

    // Use a page feed to specify precisely which URLs to use with your
    // Dynamic Search Ads.
    PageFeed pageFeed = new PageFeed();
    pageFeed.setFeedIds(new long[] {feedDetails.feedId});
    dsaSetting.setPageFeed(pageFeed);

    // Optional: Specify whether only the supplied URLs should be used with your
    // Dynamic Search Ads.
    dsaSetting.setUseSuppliedUrlsOnly(true);

    Campaign updatedCampaign = new Campaign();
    updatedCampaign.setId(campaignId);
    updatedCampaign.setSettings(campaign.getSettings());

    CampaignOperation operation = new CampaignOperation();
    operation.setOperand(updatedCampaign);
    operation.setOperator(Operator.SET);

    updatedCampaign = campaignService.mutate(new CampaignOperation[] {operation}).getValue(0);
    System.out.printf(
        "DSA page feed for campaign ID %d was updated with feed ID %d.%n",
        updatedCampaign.getId(), feedDetails.feedId);
  }

  /**
   * Sets custom targeting for the page feed URLs based on a list of labels.
   *
   * @param adWordsServices
   * @param session
   * @param adGroupId
   * @param dsaPageUrlLabel
   */
  private static void addDsaTargeting(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      Long adGroupId,
      String dsaPageUrlLabel)
      throws ApiException, RemoteException {
    // Get the AdGroupCriterionService.
    AdGroupCriterionServiceInterface adGroupCriterionService =
        adWordsServices.get(session, AdGroupCriterionServiceInterface.class);

    // Create a webpage criterion.
    Webpage webpage = new Webpage();

    WebpageParameter parameter = new WebpageParameter();
    parameter.setCriterionName("Test criterion");
    webpage.setParameter(parameter);

    // Add a condition for label=specified_label_name.
    WebpageCondition condition = new WebpageCondition();
    condition.setOperand(WebpageConditionOperand.CUSTOM_LABEL);
    condition.setArgument(dsaPageUrlLabel);
    parameter.setConditions(new WebpageCondition[] {condition});

    BiddableAdGroupCriterion criterion = new BiddableAdGroupCriterion();
    criterion.setAdGroupId(adGroupId);
    criterion.setCriterion(webpage);

    // Set a custom bid for this criterion.
    BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();

    CpcBid cpcBid = new CpcBid();
    Money money = new Money();
    money.setMicroAmount(1_500_000L);
    cpcBid.setBid(money);
    biddingStrategyConfiguration.setBids(new Bids[] {cpcBid});

    criterion.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

    AdGroupCriterionOperation operation = new AdGroupCriterionOperation();
    operation.setOperand(criterion);
    operation.setOperator(Operator.ADD);

    BiddableAdGroupCriterion newCriterion =
        (BiddableAdGroupCriterion)
            adGroupCriterionService.mutate(new AdGroupCriterionOperation[] {operation}).getValue(0);
    System.out.printf(
        "Web page criterion with ID %d and status '%s' was created.%n",
        newCriterion.getCriterion().getId(), newCriterion.getUserStatus());
  }
}

Add a DSA campaign

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroup;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupStatus;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupType;
import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.BiddableAdGroupCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyType;
import com.google.api.ads.adwords.axis.v201809.cm.Bids;
import com.google.api.ads.adwords.axis.v201809.cm.Budget;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetBudgetDeliveryMethod;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Campaign;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus;
import com.google.api.ads.adwords.axis.v201809.cm.CpcBid;
import com.google.api.ads.adwords.axis.v201809.cm.DynamicSearchAdsSetting;
import com.google.api.ads.adwords.axis.v201809.cm.ExpandedDynamicSearchAd;
import com.google.api.ads.adwords.axis.v201809.cm.Money;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.Setting;
import com.google.api.ads.adwords.axis.v201809.cm.UserStatus;
import com.google.api.ads.adwords.axis.v201809.cm.Webpage;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageCondition;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageConditionOperand;
import com.google.api.ads.adwords.axis.v201809.cm.WebpageParameter;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import org.joda.time.DateTime;

/**
 * This code example adds a Dynamic Search Ads campaign. To get campaigns, run GetCampaigns.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddDynamicSearchAdsCampaign {

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    try {
      runExample(adWordsServices, session);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws RemoteException {
    Budget budget = createBudget(adWordsServices, session);

    Campaign campaign = createCampaign(adWordsServices, session, budget);
    AdGroup adGroup = createAdGroup(adWordsServices, session, campaign);
    createExpandedDSA(adWordsServices, session, adGroup);
    addWebPageCriteria(adWordsServices, session, adGroup);
  }

  /** Creates the campaign. */
  private static Campaign createCampaign(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, Budget budget)
      throws RemoteException, ApiException {
    // Get the CampaignService.
    CampaignServiceInterface campaignService =
        adWordsServices.get(session, CampaignServiceInterface.class);

    // Create campaign.
    Campaign campaign = new Campaign();
    campaign.setName("Interplanetary Cruise #" + System.currentTimeMillis());
    campaign.setAdvertisingChannelType(AdvertisingChannelType.SEARCH);

    // Recommendation: Set the campaign to PAUSED when creating it to prevent
    // the ads from immediately serving. Set to ENABLED once you've added
    // targeting and the ads are ready to serve.
    campaign.setStatus(CampaignStatus.PAUSED);

    BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();
    biddingStrategyConfiguration.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC);
    campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

    // Only the budgetId should be sent, all other fields will be ignored by CampaignService.
    Budget campaignBudget = new Budget();
    campaignBudget.setBudgetId(budget.getBudgetId());
    campaign.setBudget(campaignBudget);

    // Required: Set the campaign's Dynamic Search Ads settings.
    DynamicSearchAdsSetting dynamicSearchAdsSetting = new DynamicSearchAdsSetting();
    // Required: Set the domain name and language.
    dynamicSearchAdsSetting.setDomainName("example.com");
    dynamicSearchAdsSetting.setLanguageCode("en");

    // Set the campaign settings.
    campaign.setSettings(new Setting[] {dynamicSearchAdsSetting});

    // Optional: Set the start date.
    campaign.setStartDate(DateTime.now().plusDays(1).toString("yyyyMMdd"));
    // Optional: Set the end date.
    campaign.setEndDate(DateTime.now().plusYears(1).toString("yyyyMMdd"));

    // Create the operation.
    CampaignOperation operation = new CampaignOperation();
    operation.setOperand(campaign);
    operation.setOperator(Operator.ADD);

    // Add the campaign.
    Campaign newCampaign = campaignService.mutate(new CampaignOperation[] {operation}).getValue(0);

    // Display the results.
    System.out.printf(
        "Campaign with name '%s' and ID %d was added.%n",
        newCampaign.getName(), newCampaign.getId());

    return newCampaign;
  }

  /** Creates the budget. */
  private static Budget createBudget(
      AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws RemoteException, ApiException {
    // Get the BudgetService.
    BudgetServiceInterface budgetService =
        adWordsServices.get(session, BudgetServiceInterface.class);

    // Create a budget, which can be shared by multiple campaigns.
    Budget sharedBudget = new Budget();
    sharedBudget.setName("Interplanetary Cruise #" + System.currentTimeMillis());
    Money budgetAmount = new Money();
    budgetAmount.setMicroAmount(50000000L);
    sharedBudget.setAmount(budgetAmount);
    sharedBudget.setDeliveryMethod(BudgetBudgetDeliveryMethod.STANDARD);

    BudgetOperation budgetOperation = new BudgetOperation();
    budgetOperation.setOperand(sharedBudget);
    budgetOperation.setOperator(Operator.ADD);

    // Add the budget
    Budget budget = budgetService.mutate(new BudgetOperation[] {budgetOperation}).getValue(0);
    return budget;
  }

  /** Creates the ad group. */
  private static AdGroup createAdGroup(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, Campaign campaign)
      throws ApiException, RemoteException {
    // Get the AdGroupService.
    AdGroupServiceInterface adGroupService =
        adWordsServices.get(session, AdGroupServiceInterface.class);

    // Create the ad group.
    AdGroup adGroup = new AdGroup();

    // Required: Set the ad group's type to Dynamic Search Ads.
    adGroup.setAdGroupType(AdGroupType.SEARCH_DYNAMIC_ADS);

    adGroup.setName("Earth to Mars Cruises #" + System.currentTimeMillis());
    adGroup.setCampaignId(campaign.getId());
    adGroup.setStatus(AdGroupStatus.PAUSED);

    // Recommended: Set a tracking URL template for your ad group if you want to use URL
    // tracking software.
    adGroup.setTrackingUrlTemplate("http://tracker.example.com/traveltracker/{escapedlpurl}");
    
    // Set the ad group bids.
    BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration();

    CpcBid cpcBid = new CpcBid();
    cpcBid.setBid(new Money());
    cpcBid.getBid().setMicroAmount(3000000L);

    biddingConfig.setBids(new Bids[] {cpcBid});

    adGroup.setBiddingStrategyConfiguration(biddingConfig);

    // Create the operation.
    AdGroupOperation operation = new AdGroupOperation();
    operation.setOperand(adGroup);
    operation.setOperator(Operator.ADD);

    AdGroup newAdGroup = adGroupService.mutate(new AdGroupOperation[] {operation}).getValue(0);
    System.out.printf(
        "Ad group with name '%s' and ID %d was added.%n", newAdGroup.getName(), newAdGroup.getId());
    return newAdGroup;
  }

  /** Creates the expanded Dynamic Search Ad. */
  private static void createExpandedDSA(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, AdGroup adGroup)
      throws ApiException, RemoteException {
    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    // Create the expanded Dynamic Search Ad. This ad will have its headline and final URL
    // auto-generated at serving time according to domain name specific information provided
    // by DynamicSearchAdsSetting at the campaign level.
    ExpandedDynamicSearchAd expandedDSA = new ExpandedDynamicSearchAd();
    // Set the ad description.
    expandedDSA.setDescription("Buy your tickets now!");
    expandedDSA.setDescription2("Discount ends soon");

    // Create the ad group ad.
    AdGroupAd adGroupAd = new AdGroupAd();
    adGroupAd.setAdGroupId(adGroup.getId());
    adGroupAd.setAd(expandedDSA);

    // Optional: Set the status.
    adGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create the operation.
    AdGroupAdOperation operation = new AdGroupAdOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(adGroupAd);

    // Create the ad.
    AdGroupAd newAdGroupAd =
        adGroupAdService.mutate(new AdGroupAdOperation[] {operation}).getValue(0);
    ExpandedDynamicSearchAd newExpandedDSA = (ExpandedDynamicSearchAd) newAdGroupAd.getAd();
    System.out.printf(
        "Expanded Dynamic Search Ad with ID %d and description '%s' and description 2 '%s' was "
            + "added.%n",
        newExpandedDSA.getId(), newExpandedDSA.getDescription(), newExpandedDSA.getDescription2());
  }

  /** Adds a web page criteria to target Dynamic Search Ads. */
  private static void addWebPageCriteria(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, AdGroup adGroup)
      throws ApiException, RemoteException {
    // Get the AdGroupCriterionService.
    AdGroupCriterionServiceInterface adGroupCriterionService =
        adWordsServices.get(session, AdGroupCriterionServiceInterface.class);

    // Create a webpage criterion for special offers.
    WebpageParameter param = new WebpageParameter();
    param.setCriterionName("Special offers");

    WebpageCondition urlCondition = new WebpageCondition();
    urlCondition.setOperand(WebpageConditionOperand.URL);
    urlCondition.setArgument("/specialoffers");

    WebpageCondition titleCondition = new WebpageCondition();
    titleCondition.setOperand(WebpageConditionOperand.PAGE_TITLE);
    titleCondition.setArgument("Special Offer");

    param.setConditions(new WebpageCondition[] {urlCondition, titleCondition});

    Webpage webpage = new Webpage();
    webpage.setParameter(param);

    // Create biddable ad group criterion.
    BiddableAdGroupCriterion biddableAdGroupCriterion = new BiddableAdGroupCriterion();
    biddableAdGroupCriterion.setAdGroupId(adGroup.getId());
    biddableAdGroupCriterion.setCriterion(webpage);
    biddableAdGroupCriterion.setUserStatus(UserStatus.PAUSED);

    // Optional: set a custom bid.
    BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();
    CpcBid bid = new CpcBid();
    bid.setBid(new Money());
    bid.getBid().setMicroAmount(10000000L);
    biddingStrategyConfiguration.setBids(new Bids[] {bid});
    biddableAdGroupCriterion.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

    // Create operations.
    AdGroupCriterionOperation operation = new AdGroupCriterionOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(biddableAdGroupCriterion);

    // Create the criterion.
    AdGroupCriterion newAdGroupCriterion =
        adGroupCriterionService.mutate(new AdGroupCriterionOperation[] {operation}).getValue(0);

    System.out.printf(
        "Webpage criterion with ID %d was added to ad group ID %d.%n",
        newAdGroupCriterion.getCriterion().getId(), newAdGroupCriterion.getAdGroupId());
  }
}

Add an expanded text ad with Upgraded URLs

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.CustomParameter;
import com.google.api.ads.adwords.axis.v201809.cm.CustomParameters;
import com.google.api.ads.adwords.axis.v201809.cm.ExpandedTextAd;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;

/**
 * This example adds an expanded text ad that uses advanced features of upgraded URLs.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class AddExpandedTextAdWithUpgradedUrls {

  private static class AddExpandedTextAdWithUpgradedUrlsParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddExpandedTextAdWithUpgradedUrlsParams params = new AddExpandedTextAdWithUpgradedUrlsParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where the ad will be created.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId)
      throws RemoteException {
    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    // Create expanded text ad with a tracking template and custom parameters.
    ExpandedTextAd expandedTextAd = new ExpandedTextAd();
    expandedTextAd.setHeadlinePart1("Luxury Cruise to Mars");
    expandedTextAd.setHeadlinePart2("Visit the Red Planet in style.");
    expandedTextAd.setDescription("Low-gravity fun for everyone!");

    // Specify a tracking url for 3rd party tracking provider. You may
    // specify one at customer, campaign, ad group, ad, criterion or
    // feed item levels.
    expandedTextAd.setTrackingUrlTemplate(
        "http://tracker.example.com/?season={_season}&promocode={_promocode}&u={lpurl}");

    // Since your tracking url has two custom parameters, provide their
    // values too. This can be provided at campaign, ad group, ad, criterion
    // or feed item levels.
    CustomParameter seasonParameter = new CustomParameter();
    seasonParameter.setKey("season");
    seasonParameter.setValue("christmas");

    CustomParameter promoCodeParameter = new CustomParameter();
    promoCodeParameter.setKey("promocode");
    promoCodeParameter.setValue("NYC123");

    CustomParameters trackingUrlParameters = new CustomParameters();
    trackingUrlParameters.setParameters(
        new CustomParameter[] {seasonParameter, promoCodeParameter});
    expandedTextAd.setUrlCustomParameters(trackingUrlParameters);

    // Specify a list of final urls. This field cannot be set if url field is
    // set. This may be specified at ad, criterion, and feed item levels.
    expandedTextAd.setFinalUrls(new String[] {"http://www.example.com/cruise/space/",
        "http://www.example.com/locations/mars/"});
    
    // Specify a list of final mobile urls. This field cannot be set if url field is
    // set or finalUrls is not set. This may be specified at ad, criterion, and feed
    // item levels.
    expandedTextAd.setFinalMobileUrls(new String[] {"http://mobile.example.com/cruise/space/",
        "http://mobile.example.com/locations/mars/"});

    // Create ad group ad.
    AdGroupAd textAdGroupAd = new AdGroupAd();
    textAdGroupAd.setAdGroupId(adGroupId);
    textAdGroupAd.setAd(expandedTextAd);

    // Optional: Set status.
    textAdGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create operation.
    AdGroupAdOperation textAdGroupAdOperation = new AdGroupAdOperation();
    textAdGroupAdOperation.setOperand(textAdGroupAd);
    textAdGroupAdOperation.setOperator(Operator.ADD);

    AdGroupAdOperation[] operations =
        new AdGroupAdOperation[] {textAdGroupAdOperation};

    // Add ad.
    AdGroupAd adGroupAdResult = adGroupAdService.mutate(operations).getValue(0);

    // Display ad.
    System.out.printf("Ad with ID %d and tracking URL template '%s' was added.",
        adGroupAdResult.getAd().getId(), adGroupAdResult.getAd().getTrackingUrlTemplate());
  }
}

Add a Gmail ad to an ad group

// Copyright 2018 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.GmailAd;
import com.google.api.ads.adwords.axis.v201809.cm.GmailTeaser;
import com.google.api.ads.adwords.axis.v201809.cm.Image;
import com.google.api.ads.adwords.axis.v201809.cm.Media;
import com.google.api.ads.adwords.axis.v201809.cm.MediaMediaType;
import com.google.api.ads.adwords.axis.v201809.cm.MediaServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.io.IOException;
import java.rmi.RemoteException;

/**
 * This example adds a Gmail ad to a given ad group. The ad group's campaign needs to have an
 * AdvertisingChannelType of DISPLAY and AdvertisingChannelSubType of DISPLAY_GMAIL_AD. To get ad
 * groups, run GetAdGroups.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddGmailAd {

  private static class AddGmailAdParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddGmailAdParams params = new AddGmailAdParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re);
    } catch (IOException ioe) {
      System.err.printf("Example failed due to IOException: %s%n", ioe);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where the ad will be created.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   * @throws IOException if unable to get media data from the URL.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId)
      throws IOException {
    // This ad format does not allow the creation of an image using the
    // Image.data field. An image must first be created using the MediaService,
    // and Image.mediaId must be populated when creating the ad.
    long logoImageId = uploadImage(adWordsServices, session, "https://goo.gl/mtt54n");
    Image logoImage = new Image();
    logoImage.setMediaId(logoImageId);

    long marketingImageId = uploadImage(adWordsServices, session, "http://goo.gl/3b9Wfh");
    Image adImage = new Image();
    adImage.setMediaId(marketingImageId);

    GmailTeaser teaser = new GmailTeaser();
    teaser.setHeadline("Dream");
    teaser.setDescription("Create your own adventure");
    teaser.setBusinessName("Interplanetary Ships");
    teaser.setLogoImage(logoImage);

    // Create the Gmail ad.
    GmailAd gmailAd = new GmailAd();
    gmailAd.setTeaser(teaser);
    gmailAd.setMarketingImage(adImage);
    gmailAd.setMarketingImageHeadline("Travel");
    gmailAd.setMarketingImageDescription("Take to the skies!");
    gmailAd.setFinalUrls(new String[] {"http://www.example.com"});

    // Create ad group ad for the Gmail ad.
    AdGroupAd adGroupAd = new AdGroupAd();
    adGroupAd.setAdGroupId(adGroupId);
    adGroupAd.setAd(gmailAd);
    // Additional properties (non-required).
    adGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create operation.
    AdGroupAdOperation operation = new AdGroupAdOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(adGroupAd);

    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    // Add Gmail ad.
    AdGroupAdReturnValue returnValue =
        adGroupAdService.mutate(new AdGroupAdOperation[] {operation});

    if (returnValue.getValue() != null) {
      for (AdGroupAd newAdGroupAd : returnValue.getValue()) {
        System.out.printf(
            "New Gmail ad with ID %d and headline '%s' was added.%n",
            newAdGroupAd.getAd().getId(),
            ((GmailAd) newAdGroupAd.getAd()).getTeaser().getHeadline());
      }
    } else {
      System.out.println("No Gmail ads were added.");
    }
  }

  /** Uploads an image. */
  private static long uploadImage(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, String url)
      throws IOException {
    MediaServiceInterface mediaService = adWordsServices.get(session, MediaServiceInterface.class);

    // Create image.
    Image image = new Image();
    image.setData(com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl(url));
    image.setType(MediaMediaType.IMAGE);

    Media[] media = new Media[] {image};

    // Upload image.
    Media[] result = mediaService.upload(media);

    return result[0].getMediaId();
  }
}

Add an HTML 5 ad to an ad group

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.Dimensions;
import com.google.api.ads.adwords.axis.v201809.cm.MediaBundle;
import com.google.api.ads.adwords.axis.v201809.cm.MediaMediaType;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.TemplateAd;
import com.google.api.ads.adwords.axis.v201809.cm.TemplateElement;
import com.google.api.ads.adwords.axis.v201809.cm.TemplateElementField;
import com.google.api.ads.adwords.axis.v201809.cm.TemplateElementFieldType;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.io.IOException;
import java.rmi.RemoteException;

/**
 * This example adds an HTML5 ad to given ad group. To get
 * ad groups, run GetAdGroups.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class AddHtml5Ad {

  private static class AddHtml5AdParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddHtml5AdParams params = new AddHtml5AdParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re);
    } catch (IOException ioe) {
      System.err.printf("Example failed due to IOException: %s%n", ioe);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where the ad will be created.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   * @throws IOException if unable to get media data from the URL.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId)
      throws IOException {
    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    // Create the template ad.
    TemplateAd html5Ad = new TemplateAd();
    html5Ad.setName("Ad for HTML5");
    html5Ad.setTemplateId(419L);
    html5Ad.setFinalUrls(new String[] {"http://example.com/html5"});
    html5Ad.setDisplayUrl("example.com/html5");

    Dimensions dimensions = new Dimensions();
    dimensions.setWidth(300);
    dimensions.setHeight(250);
    html5Ad.setDimensions(dimensions);

    // The HTML5 zip file contains all the HTML, CSS, and images needed for the
    // HTML5 ad. For help on creating an HTML5 zip file, check out Google Web
    // Designer (https://www.google.com/webdesigner/).
    byte[] html5Zip =
        com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl("https://goo.gl/9Y7qI2");

    // Create a media bundle containing the zip file with all the HTML5 components.
    // NOTE: You may also upload an HTML5 zip using MediaService.upload()
    // and simply set the mediaId field below. See UploadMediaBundle.java for an example.
    MediaBundle mediaBundle = new MediaBundle();
    mediaBundle.setData(html5Zip);
    mediaBundle.setEntryPoint("carousel/index.html");
    mediaBundle.setType(MediaMediaType.MEDIA_BUNDLE);

    // Create the template elements for the ad. You can refer to
    // https://developers.google.com/adwords/api/docs/appendix/templateads
    // for the list of available template fields.
    TemplateElementField media = new TemplateElementField();
    media.setName("Custom_layout");
    media.setFieldMedia(mediaBundle);
    media.setType(TemplateElementFieldType.MEDIA_BUNDLE);

    TemplateElementField layout = new TemplateElementField();
    layout.setName("layout");
    layout.setFieldText("Custom");
    layout.setType(TemplateElementFieldType.ENUM);

    TemplateElement adData = new TemplateElement();
    adData.setUniqueName("adData");
    adData.setFields(new TemplateElementField[] {media, layout});

    html5Ad.setTemplateElements(new TemplateElement[] {adData});

    // Create the AdGroupAd.
    AdGroupAd html5AdGroupAd = new AdGroupAd();
    html5AdGroupAd.setAdGroupId(adGroupId);
    html5AdGroupAd.setAd(html5Ad);

    // Optional: Set the status.
    html5AdGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create the operation.
    AdGroupAdOperation operation = new AdGroupAdOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(html5AdGroupAd);

    // Create the ads.
    AdGroupAdReturnValue result = adGroupAdService.mutate(new AdGroupAdOperation[] {operation});

    for (AdGroupAd adGroupAd : result.getValue()) {
      System.out.printf("New HTML5 ad with ID %d and display url '%s' was created.%n",
          adGroupAd.getAd().getId(), adGroupAd.getAd().getDisplayUrl());
    }
  }
}

Add a multi-asset responsive display ad to an ad group

// Copyright 2018 Google LLC
//
// 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
//
//     https://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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.AssetLink;
import com.google.api.ads.adwords.axis.v201809.cm.AssetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AssetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.DisplayAdFormatSetting;
import com.google.api.ads.adwords.axis.v201809.cm.ImageAsset;
import com.google.api.ads.adwords.axis.v201809.cm.MultiAssetResponsiveDisplayAd;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.TextAsset;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This example adds a responsive display ad (MultiAssetResponsiveDisplayAd) to an ad group. Image
 * assets are uploaded using AssetService. To get ad groups, run GetAdGroups.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddMultiAssetResponsiveDisplayAd {

  private static class AddMultiAssetResponsiveDisplayAdParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddMultiAssetResponsiveDisplayAdParams params = new AddMultiAssetResponsiveDisplayAdParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re);
    } catch (IOException ioe) {
      System.err.printf("Example failed unexpectedly due to IOException: %s%n", ioe);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where the ad will be created.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   * @throws IOException if unable to retrieve an image from a URL.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId)
      throws IOException {
    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    List<AdGroupAdOperation> operations = new ArrayList<>();

    MultiAssetResponsiveDisplayAd ad = new MultiAssetResponsiveDisplayAd();
    List<AssetLink> headlines = new ArrayList<>();
    headlines.add(createAssetLinkForText("Travel to Mars"));
    headlines.add(createAssetLinkForText("Travel to Jupiter"));
    headlines.add(createAssetLinkForText("Travel to Pluto"));
    headlines.add(createAssetLinkForText("Experience the Stars"));
    ad.setHeadlines(headlines.toArray(new AssetLink[0]));

    List<AssetLink> descriptions = new ArrayList<>();
    descriptions.add(createAssetLinkForText("Visit the planet in a luxury spaceship."));
    descriptions.add(createAssetLinkForText("See the planet in style."));
    ad.setDescriptions(descriptions.toArray(new AssetLink[0]));

    ad.setBusinessName("Galactic Luxury Cruises");
    ad.setLongHeadline(createAssetLinkForText("Visit the planet in a luxury spaceship."));

    // This ad format does not allow the creation of an image asset by setting the asset.imageData
    // field. An image asset must first be created using the AssetService, and asset.assetId must be
    // populated when creating the ad.
    ad.setMarketingImages(
        new AssetLink[] {
          createAssetLinkForImageAsset(
              uploadImageAsset(adWordsServices, session, "https://goo.gl/3b9Wfh"))
        });
    ad.setSquareMarketingImages(
        new AssetLink[] {
          createAssetLinkForImageAsset(
              uploadImageAsset(adWordsServices, session, "https://goo.gl/mtt54n"))
        });

    ad.setFinalUrls(new String[] {"http://www.example.com"});

    // Optional: set call to action text.
    ad.setCallToActionText("Shop Now");

    // Set color settings using hexadecimal values. Set allowFlexibleColor to false if you want
    // your ads to render by always using your colors strictly.
    ad.setMainColor("#0000ff");
    ad.setAccentColor("#ffff00");
    ad.setAllowFlexibleColor(false);

    // Set the format setting that the ad will be served in.
    ad.setFormatSetting(DisplayAdFormatSetting.NON_NATIVE);

    // Optional: Set dynamic display ad settings, composed of landscape logo image, promotion text,
    // and price prefix.
    ad.setDynamicSettingsPricePrefix("as low as");
    ad.setDynamicSettingsPromoText("Free shipping!");
    ad.setLogoImages(
        new AssetLink[] {
          createAssetLinkForImageAsset(
              uploadImageAsset(adWordsServices, session, "https://goo.gl/mtt54n"))
        });

    // Create ad group ad.
    AdGroupAd adGroupAd = new AdGroupAd();
    adGroupAd.setAdGroupId(adGroupId);
    adGroupAd.setAd(ad);

    // Optional: set the status.
    adGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create the operation.
    AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation();
    adGroupAdOperation.setOperand(adGroupAd);
    adGroupAdOperation.setOperator(Operator.ADD);

    operations.add(adGroupAdOperation);

    // Add ad.
    AdGroupAdReturnValue result =
        adGroupAdService.mutate(operations.toArray(new AdGroupAdOperation[operations.size()]));

    Arrays.stream(result.getValue())
        .map(adGroupAdResult -> (MultiAssetResponsiveDisplayAd) adGroupAdResult.getAd())
        .forEach(
            newAd ->
                System.out.printf(
                    "New responsive display ad with ID %d and long headline '%s' was added.%n",
                    newAd.getId(),
                    ((TextAsset) newAd.getLongHeadline().getAsset()).getAssetText()));
  }

  /**
   * Creates an {@link AssetLink} containing a {@link TextAsset} with the specified string.
   *
   * @param text the text for the text asset.
   * @return a new {@link AssetLink}
   */
  private static AssetLink createAssetLinkForText(String text) {
    AssetLink assetLink = new AssetLink();
    TextAsset textAsset = new TextAsset();
    textAsset.setAssetText(text);
    assetLink.setAsset(textAsset);
    return assetLink;
  }

  /**
   * Creates an {@link AssetLink} containing a {@link ImageAsset} with the specified asset ID.
   *
   * @param assetId ID of the image asset.
   * @return a new {@link AssetLink}
   */
  private static AssetLink createAssetLinkForImageAsset(long assetId) {
    AssetLink assetLink = new AssetLink();
    ImageAsset imageAsset = new ImageAsset();
    imageAsset.setAssetId(assetId);
    assetLink.setAsset(imageAsset);
    return assetLink;
  }

  /**
   * Creates and uploads an {@link ImageAsset} for the specified URL.
   *
   * @return the ID of the {@link ImageAsset}.
   * @throws IOException if unable to read the image from the specified URL.
   */
  private static long uploadImageAsset(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, String url)
      throws IOException {

    AssetServiceInterface assetService = adWordsServices.get(session, AssetServiceInterface.class);

    // Create the image asset.
    ImageAsset image = new ImageAsset();
    // Optional: Provide a unique friendly name to identify your asset. If you specify the assetName
    // field, then both the asset name and the image being uploaded should be unique, and should not
    // match another ACTIVE asset in this customer account.
    // image.setAssetName("Image asset #" + System.currentTimeMillis());
    image.setImageData(com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl(url));

    // Create the operation.
    AssetOperation operation = new AssetOperation();
    operation.setOperator(Operator.ADD);
    operation.setOperand(image);

    // Create the asset and return the ID.
    return assetService.mutate(new AssetOperation[] {operation}).getValue(0).getAssetId();
  }
}

Add a responsive display ad

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdStatus;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.DynamicSettings;
import com.google.api.ads.adwords.axis.v201809.cm.Image;
import com.google.api.ads.adwords.axis.v201809.cm.Media;
import com.google.api.ads.adwords.axis.v201809.cm.MediaMediaType;
import com.google.api.ads.adwords.axis.v201809.cm.MediaServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.ResponsiveDisplayAd;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Arrays;

/**
 * This example adds an image representing the ad using the MediaService and then adds a responsive
 * display ad to a given ad group. To get ad groups, run GetAdGroups.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class AddResponsiveDisplayAd {

  private static class AddResponsiveDisplayAdParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
    private Long adGroupId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    AddResponsiveDisplayAdParams params = new AddResponsiveDisplayAdParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.adGroupId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re);
    } catch (IOException ioe) {
      System.err.printf("Example failed due to IOException: %s%n", ioe);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param adGroupId the ID of the ad group where the ad will be created.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   * @throws IOException if uploading an image failed.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices, AdWordsSession session, long adGroupId)
      throws IOException {
    // Get the MediaService.
    MediaServiceInterface mediaService = adWordsServices.get(session, MediaServiceInterface.class);

    // Get the AdGroupAdService.
    AdGroupAdServiceInterface adGroupAdService =
        adWordsServices.get(session, AdGroupAdServiceInterface.class);

    // Create a responsive display ad.
    ResponsiveDisplayAd responsiveDisplayAd = new ResponsiveDisplayAd();

    // This ad format does not allow the creation of an image using the
    // Image.data field. An image must first be created using the MediaService,
    // and Image.mediaId must be populated when creating the ad.
    long marketingImageMediaId = uploadImage(mediaService, "https://goo.gl/3b9Wfh");
    Image marketingImage = new Image();
    marketingImage.setMediaId(marketingImageMediaId);
    responsiveDisplayAd.setMarketingImage(marketingImage);

    responsiveDisplayAd.setShortHeadline("Travel");
    responsiveDisplayAd.setLongHeadline("Travel the World");
    responsiveDisplayAd.setDescription("Take to the air!");
    responsiveDisplayAd.setBusinessName("Interplanetary Cruises");
    responsiveDisplayAd.setFinalUrls(new String[] {"http://www.example.com/"});

    // Optional: Create a square marketing image using MediaService, and set it
    // to the ad.
    long squareMarketingImageMediaId = uploadImage(mediaService, "https://goo.gl/mtt54n");
    Image squareMarketingImage = new Image();
    squareMarketingImage.setMediaId(squareMarketingImageMediaId);
    responsiveDisplayAd.setSquareMarketingImage(squareMarketingImage);

    // Optional: set call to action text.
    responsiveDisplayAd.setCallToActionText("Shop Now");

    // Optional: Set dynamic display ad settings, composed of landscape logo
    // image, promotion text, and price prefix.
    DynamicSettings dynamicDisplayAdSettings = createDynamicDisplayAdSettings(mediaService);
    responsiveDisplayAd.setDynamicDisplayAdSettings(dynamicDisplayAdSettings);

    // Whitelisted accounts only: Set color settings using hexadecimal values.
    // Set allowFlexibleColor to false if you want your ads to render by always
    // using your colors strictly.
    /*
    responsiveDisplayAd.setMainColor("#0000ff");
    responsiveDisplayAd.setAccentColor("#ffff00");
    responsiveDisplayAd.setAllowFlexibleColor(false);
    */

    // Whitelisted accounts only: Set the format setting that the ad will be
    // served in.
    /*
    responsiveDisplayAd.setFormatSetting(
        com.google.api.ads.adwords.axis.v201809.cm.DisplayAdFormatSetting.NON_NATIVE);
    */

    // Create ad group ad for the responsive display ad.
    AdGroupAd adGroupAd = new AdGroupAd();
    adGroupAd.setAdGroupId(adGroupId);
    adGroupAd.setAd(responsiveDisplayAd);

    // Optional: set the status.
    adGroupAd.setStatus(AdGroupAdStatus.PAUSED);

    // Create the operation.
    AdGroupAdOperation adGroupAdOperation = new AdGroupAdOperation();
    adGroupAdOperation.setOperand(adGroupAd);
    adGroupAdOperation.setOperator(Operator.ADD);

    // Make the mutate request.
    AdGroupAdReturnValue result =
        adGroupAdService.mutate(new AdGroupAdOperation[] {adGroupAdOperation});

    // Display ads.
    Arrays.stream(result.getValue())
        .map(adGroupAdResult -> (ResponsiveDisplayAd) adGroupAdResult.getAd())
        .forEach(
            newAd ->
                System.out.printf(
                    "Responsive display ad with ID %d and short headline '%s' was added.%n",
                    newAd.getId(), newAd.getShortHeadline()));
  }

  private static DynamicSettings createDynamicDisplayAdSettings(MediaServiceInterface mediaService)
      throws IOException {
    long logoImageMediaId = uploadImage(mediaService, "https://goo.gl/dEvQeF");
    Image logo = new Image();
    logo.setMediaId(logoImageMediaId);

    DynamicSettings dynamicSettings = new DynamicSettings();
    dynamicSettings.setLandscapeLogoImage(logo);
    dynamicSettings.setPricePrefix("as low as");
    dynamicSettings.setPromoText("Free shipping!");
    return dynamicSettings;
  }

  /**
   * Uploads the image from the specified {@code url} via {@code MediaService}.
   *
   * @return the {@code mediaId} of the uploaded image.
   */
  private static long uploadImage(MediaServiceInterface mediaService, String url)
      throws IOException {
    // Create image.
    Image image = new Image();
    image.setType(MediaMediaType.IMAGE);
    image.setData(com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl(url));

    // Upload image.
    Image uploadedImage = (Image) mediaService.upload(new Media[] {image})[0];
    return uploadedImage.getMediaId();
  }
}

Add a Shopping dynamic remarketing campaign

// Copyright 2018 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroup;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAd;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupAdServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupOperation;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupStatus;
import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.BiddableAdGroupCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyType;
import com.google.api.ads.adwords.axis.v201809.cm.Budget;
import com.google.api.ads.adwords.axis.v201809.cm.Campaign;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus;
import com.google.api.ads.adwords.axis.v201809.cm.CriterionUserList;
import com.google.api.ads.adwords.axis.v201809.cm.DynamicSettings;
import com.google.api.ads.adwords.axis.v201809.cm.Image;
import com.google.api.ads.adwords.axis.v201809.cm.Media;
import com.google.api.ads.adwords.axis.v201809.cm.MediaMediaType;
import com.google.api.ads.adwords.axis.v201809.cm.MediaServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.ResponsiveDisplayAd;
import com.google.api.ads.adwords.axis.v201809.cm.Setting;
import com.google.api.ads.adwords.axis.v201809.cm.ShoppingSetting;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.client.AdWordsSession.Builder;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.io.IOException;
import java.rmi.RemoteException;

/**
 * This example adds a Shopping dynamic remarketing campaign for the Display Network via the
 * following steps:
 *
 * <ul>
 *   <li>Creates a new Display Network campaign.
 *   <li>Links the campaign with Merchant Center.
 *   <li>Links the user list to the ad group.
 *   <li>Creates a responsive display ad to render the dynamic text.
 * </ul>
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddShoppingDynamicRemarketingCampaign {

  private static class AddShoppingDynamicRemarketingCampaignParams extends CodeSampleParams {

    @Parameter(names = ArgumentNames.MERCHANT_ID, required = true)
    private long merchantId;

    @Parameter(names = ArgumentNames.BUDGET_ID, required = true)
    private long budgetId;

    @Parameter(names = ArgumentNames.USER_LIST_ID, required = true)
    private long userListId;
  }

  public static void main(String[] args) {
    final AdWordsServicesInterface services = AdWordsServices.getInstance();
    AdWordsSession session;

    try {
      Credential oAuth2Credential;
      oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(OfflineCredentials.Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();
      session = new Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file%n", DEFAULT_CONFIGURATION_FILENAME);
      return;
    } catch (ValidationException ve) {
      System.err.printf("Invalid configuration in the %s file%n", DEFAULT_CONFIGURATION_FILENAME);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file%n",
          DEFAULT_CONFIGURATION_FILENAME);
      return;
    }

    final AddShoppingDynamicRemarketingCampaignParams params =
        new AddShoppingDynamicRemarketingCampaignParams();
    if (!params.parseArguments(args)) {
      params.merchantId = Long.parseLong("INSERT_MERCHANT_ID");
      params.budgetId = Long.parseLong("INSERT_BUDGET_ID");
      params.userListId = Long.parseLong("INSERT_USER_LIST_ID");
    }

    try {
      runExample(services, session, params.merchantId, params.budgetId, params.userListId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString.
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.print("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf("Request failed unexpectedly due to RemoteException: %s%n", re);
    } catch (IOException e) {
      System.err.printf("Request failed unexpectedly due to IOException: %s%n", e);
    }
  }

  /**
   * Runs the example.
   *
   * @param services the services factory.
   * @param session the session.
   * @param merchantId the ID of the merchant center account from which to source product feed data.
   * @param budgetId the ID of a shared budget to associate with the campaign.
   * @param userListId the ID of a user list to target.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   * @throws IOException if the ad images failed to load.
   */
  private static void runExample(
      AdWordsServicesInterface services,
      AdWordsSession session,
      long merchantId,
      long budgetId,
      long userListId)
      throws IOException {
    Campaign campaign = createCampaign(services, session, merchantId, budgetId);
    System.out.printf(
        "Campaign with name '%s' and ID %d was added.%n", campaign.getName(), campaign.getId());

    AdGroup adGroup = createAdGroup(services, session, campaign);
    System.out.printf(
        "Ad group with name '%s' and ID %d was added.%n", adGroup.getName(), adGroup.getId());

    AdGroupAd adGroupAd = createAd(services, session, adGroup);
    System.out.printf("Responsive display ad with ID %d was added.%n", adGroupAd.getAd().getId());

    attachUserList(services, session, adGroup, userListId);
    System.out.printf(
        "User list with ID %d was attached to ad group with ID %d.%n", userListId, adGroup.getId());
  }

  /**
   * Creates a Shopping dynamic remarketing campaign object (not including ad group level and
   * below). This creates a Display campaign with the merchant center feed attached. Merchant Center
   * is used for the product information in combination with a user list which contains hits with
   * {@code ecomm_prodid} specified. See <a
   * href="https://developers.google.com/adwords-remarketing-tag/parameters#retail"/>for more
   * detail.
   *
   * @param merchantId the ID of the Merchant Center account.
   * @param budgetId the ID of the budget to use for the campaign.
   * @return the campaign that was created.
   */
  private static Campaign createCampaign(
      AdWordsServicesInterface services, AdWordsSession session, long merchantId, long budgetId)
      throws RemoteException {
    CampaignServiceInterface campaignService =
        services.get(session, CampaignServiceInterface.class);

    Campaign campaign = new Campaign();
    campaign.setName("Shopping campaign #" + System.currentTimeMillis());
    // Dynamic remarketing campaigns are only available on the Google Display Network.
    campaign.setAdvertisingChannelType(AdvertisingChannelType.DISPLAY);
    campaign.setStatus(CampaignStatus.PAUSED);

    Budget budget = new Budget();
    budget.setBudgetId(budgetId);
    campaign.setBudget(budget);

    // This example uses a Manual CPC bidding strategy, but you should select the strategy that best
    // aligns with your sales goals. More details here:
    //   https://support.google.com/adwords/answer/2472725
    BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();
    biddingStrategyConfiguration.setBiddingStrategyType(BiddingStrategyType.MANUAL_CPC);
    campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

    ShoppingSetting setting = new ShoppingSetting();
    // Campaigns with numerically higher priorities take precedence over those with lower
    // priorities.
    setting.setCampaignPriority(0);

    // Set the Merchant Center account ID from which to source products.
    setting.setMerchantId(merchantId);

    // Display Network campaigns do not support partition by country. The only supported value is
    // "ZZ". This signals that products from all countries are available in the campaign. The actual
    // products which serve are based on the products tagged in the user list entry.
    setting.setSalesCountry("ZZ");

    // Optional: Enable local inventory ads (items for sale in physical stores.)
    setting.setEnableLocal(true);

    campaign.setSettings(new Setting[] {setting});

    CampaignOperation op = new CampaignOperation();
    op.setOperand(campaign);
    op.setOperator(Operator.ADD);

    CampaignReturnValue result = campaignService.mutate(new CampaignOperation[] {op});
    return result.getValue(0);
  }

  /**
   * Creates an ad group in the specified campaign.
   *
   * @param campaign the campaign to which the ad group should be attached.
   * @return the ad group that was created.
   */
  private static AdGroup createAdGroup(
      AdWordsServicesInterface services, AdWordsSession session, Campaign campaign)
      throws RemoteException {
    AdGroupServiceInterface adGroupService = services.get(session, AdGroupServiceInterface.class);

    AdGroup group = new AdGroup();
    group.setName("Dynamic remarketing ad group");
    group.setCampaignId(campaign.getId());
    group.setStatus(AdGroupStatus.ENABLED);

    AdGroupOperation op = new AdGroupOperation();
    op.setOperand(group);
    op.setOperator(Operator.ADD);
    AdGroupReturnValue result = adGroupService.mutate(new AdGroupOperation[] {op});
    return result.getValue(0);
  }

  /**
   * Attach a user list to an ad group. The user list provides positive targeting and feed
   * information to drive the dynamic content of the ad.
   *
   * <p>Note: User lists must be attached at the ad group level for positive targeting in Shopping
   * dynamic remarketing campaigns.
   *
   * @param adGroup the ad group which will have the user list attached.
   * @param userListId the user list to use for targeting and dynamic content.
   */
  private static void attachUserList(
      AdWordsServicesInterface services, AdWordsSession session, AdGroup adGroup, long userListId)
      throws RemoteException {
    AdGroupCriterionServiceInterface adGroupCriterionService =
        services.get(session, AdGroupCriterionServiceInterface.class);

    CriterionUserList userList = new CriterionUserList();
    userList.setUserListId(userListId);
    BiddableAdGroupCriterion adGroupCriterion = new BiddableAdGroupCriterion();
    adGroupCriterion.setCriterion(userList);
    adGroupCriterion.setAdGroupId(adGroup.getId());

    AdGroupCriterionOperation op = new AdGroupCriterionOperation();
    op.setOperand(adGroupCriterion);
    op.setOperator(Operator.ADD);

    adGroupCriterionService.mutate(new AdGroupCriterionOperation[] {op});
  }

  /**
   * Creates an ad for serving dynamic content in a remarketing campaign.
   *
   * @param adGroup the ad group under which to create the ad.
   * @return the ad that was created.
   * @throws IOException if an image was not able to be loaded.
   */
  private static AdGroupAd createAd(
      AdWordsServicesInterface services, AdWordsSession session, AdGroup adGroup)
      throws IOException {
    AdGroupAdServiceInterface adService = services.get(session, AdGroupAdServiceInterface.class);

    ResponsiveDisplayAd ad = new ResponsiveDisplayAd();

    // This ad format does not allow the creation of an image using the
    // Image.data field. An image must first be created using the MediaService,
    // and Image.mediaId must be populated when creating the ad.
    ad.setMarketingImage(uploadImage(services, session, "https://goo.gl/3b9Wfh"));

    ad.setShortHeadline("Travel");
    ad.setLongHeadline("Travel the World");
    ad.setDescription("Take to the air!");
    ad.setBusinessName("Interplanetary Cruises");
    ad.setFinalUrls(new String[] {"http://www.example.com/"});

    // Optional: Call to action text.
    // Valid texts: https://support.google.com/adwords/answer/7005917
    ad.setCallToActionText("Apply Now");

    // Optional: Set dynamic display ad settings, composed of landscape logo
    // image, promotion text, and price prefix.
    DynamicSettings dynamicDisplayAdSettings = createDynamicDisplayAdSettings(services, session);
    ad.setDynamicDisplayAdSettings(dynamicDisplayAdSettings);

    Image optionalImage = uploadImage(services, session, "https://goo.gl/mtt54n");

    // Optional: Create a logo image and set it to the ad.
    ad.setLogoImage(optionalImage);

    // Optional: Create a square marketing image and set it to the ad.
    ad.setSquareMarketingImage(optionalImage);

    // Whitelisted accounts only: Set color settings using hexadecimal values.
    // Set allowFlexibleColor to false if you want your ads to render by always
    // using your colors strictly.
    /*
    ad.setMainColor("#0000ff");
    ad.setAccentColor("#ffff00");
    ad.setAllowFlexibleColor(false);
    */

    // Whitelisted accounts only: Set the format setting that the ad will be
    // served in.
    /*
    ad.setFormatSetting(
        com.google.api.ads.adwords.axis.v201809.cm.DisplayAdFormatSetting.NON_NATIVE);
    */

    AdGroupAd adGroupAd = new AdGroupAd();
    adGroupAd.setAd(ad);
    adGroupAd.setAdGroupId(adGroup.getId());

    AdGroupAdOperation op = new AdGroupAdOperation();
    op.setOperand(adGroupAd);
    op.setOperator(Operator.ADD);

    AdGroupAdReturnValue result = adService.mutate(new AdGroupAdOperation[] {op});
    return result.getValue(0);
  }

  /**
   * Creates the additional content (images, promo text, etc.) supported by dynamic ads.
   *
   * @return the DynamicSettings object to be used.
   */
  private static DynamicSettings createDynamicDisplayAdSettings(
      AdWordsServicesInterface services, AdWordsSession session) throws IOException {
    Image logo = uploadImage(services, session, "https://goo.gl/dEvQeF");

    DynamicSettings dynamicSettings = new DynamicSettings();
    dynamicSettings.setLandscapeLogoImage(logo);
    dynamicSettings.setPricePrefix("as low as");
    dynamicSettings.setPromoText("Free shipping!");
    return dynamicSettings;
  }

  /**
   * Uploads the image from the specified {@code url}.
   *
   * @return the {@code Image} that was uploaded.
   * @throws IOException if the image cannot be loaded.
   */
  private static Image uploadImage(
      AdWordsServicesInterface services, AdWordsSession session, String url) throws IOException {
    Image image = new Image();
    image.setType(MediaMediaType.IMAGE);
    image.setData(com.google.api.ads.common.lib.utils.Media.getMediaDataFromUrl(url));
    MediaServiceInterface mediaService = services.get(session, MediaServiceInterface.class);

    return (Image) mediaService.upload(new Media[] {image})[0];
  }
}

Add a universal app campaign

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelSubType;
import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyType;
import com.google.api.ads.adwords.axis.v201809.cm.Budget;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetBudgetDeliveryMethod;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Campaign;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus;
import com.google.api.ads.adwords.axis.v201809.cm.Criterion;
import com.google.api.ads.adwords.axis.v201809.cm.GeoTargetTypeSetting;
import com.google.api.ads.adwords.axis.v201809.cm.GeoTargetTypeSettingNegativeGeoTargetType;
import com.google.api.ads.adwords.axis.v201809.cm.GeoTargetTypeSettingPositiveGeoTargetType;
import com.google.api.ads.adwords.axis.v201809.cm.Language;
import com.google.api.ads.adwords.axis.v201809.cm.Location;
import com.google.api.ads.adwords.axis.v201809.cm.MobileApplicationVendor;
import com.google.api.ads.adwords.axis.v201809.cm.Money;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.Setting;
import com.google.api.ads.adwords.axis.v201809.cm.TargetCpaBiddingScheme;
import com.google.api.ads.adwords.axis.v201809.cm.UniversalAppBiddingStrategyGoalType;
import com.google.api.ads.adwords.axis.v201809.cm.UniversalAppCampaignSetting;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.joda.time.DateTime;

/**
 * This example adds a universal app campaign. To get campaigns, run GetCampaigns.java. To upload
 * image assets for this campaign, run UploadImage.java.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the "ads.properties" file.
 * See README for more info.
 */
public class AddUniversalAppCampaign {

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    try {
      runExample(adWordsServices, session);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws RemoteException {

    // Get the CampaignService.
    CampaignServiceInterface campaignService =
        adWordsServices.get(session, CampaignServiceInterface.class);

    // Create the campaign.
    Campaign campaign = new Campaign();
    campaign.setName("Interplanetary Cruise App #" + System.currentTimeMillis());

    // Recommendation: Set the campaign to PAUSED when creating it to prevent
    // the ads from immediately serving. Set to ENABLED once you've added
    // targeting and the ads are ready to serve.
    campaign.setStatus(CampaignStatus.PAUSED);

    // Set the advertising channel and subchannel types for universal app campaigns.
    campaign.setAdvertisingChannelType(AdvertisingChannelType.MULTI_CHANNEL);
    campaign.setAdvertisingChannelSubType(AdvertisingChannelSubType.UNIVERSAL_APP_CAMPAIGN);

    // Set the campaign's bidding strategy. universal app campaigns
    // only support TARGET_CPA bidding strategy.
    BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration();
    biddingConfig.setBiddingStrategyType(BiddingStrategyType.TARGET_CPA);

    // Set the target CPA to $1 / app install.
    TargetCpaBiddingScheme biddingScheme = new TargetCpaBiddingScheme();
    biddingScheme.setTargetCpa(new Money());
    biddingScheme.getTargetCpa().setMicroAmount(1000000L);

    biddingConfig.setBiddingScheme(biddingScheme);
    campaign.setBiddingStrategyConfiguration(biddingConfig);

    // Set the campaign's budget.
    campaign.setBudget(new Budget());
    campaign.getBudget().setBudgetId(createBudget(adWordsServices, session));

    // Optional: Set the start date.
    campaign.setStartDate(DateTime.now().plusDays(1).toString("yyyyMMdd"));

    // Optional: Set the end date.
    campaign.setEndDate(DateTime.now().plusYears(1).toString("yyyyMMdd"));

    // Set the campaign's assets and ad text ideas. These values will be used to
    // generate ads.
    UniversalAppCampaignSetting universalAppSetting = new UniversalAppCampaignSetting();
    universalAppSetting.setAppId("com.labpixies.colordrips");
    universalAppSetting.setAppVendor(MobileApplicationVendor.VENDOR_GOOGLE_MARKET);
    universalAppSetting.setDescription1("A cool puzzle game");
    universalAppSetting.setDescription2("Remove connected blocks");
    universalAppSetting.setDescription3("3 difficulty levels");
    universalAppSetting.setDescription4("4 colorful fun skins");

    // Optional: You can set up to 20 image assets for your campaign.
    // See UploadImage.java for an example on how to upload images.
    //
    // universalAppSetting.setImageMediaIds(new long[] { INSERT_IMAGE_MEDIA_ID_HERE });

    // Optimize this campaign for getting new users for your app.
    universalAppSetting.setUniversalAppBiddingStrategyGoalType(
        UniversalAppBiddingStrategyGoalType.OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME);

    // If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type, then also specify
    // your in-app conversion types so AdWords can focus your campaign on people who are
    // most likely to complete the corresponding in-app actions.
    // Conversion type IDs can be retrieved using ConversionTrackerService.get.
    //
    // campaign.selectiveOptimization = new SelectiveOptimization();
    // campaign.selectiveOptimization.conversionTypeIds =
    //    new long[] { INSERT_CONVERSION_TYPE_ID_1_HERE, INSERT_CONVERSION_TYPE_ID_2_HERE };

    // Optional: Set the campaign settings for Advanced location options.
    GeoTargetTypeSetting geoSetting = new GeoTargetTypeSetting();
    geoSetting.setPositiveGeoTargetType(
        GeoTargetTypeSettingPositiveGeoTargetType.LOCATION_OF_PRESENCE);
    geoSetting.setNegativeGeoTargetType(GeoTargetTypeSettingNegativeGeoTargetType.DONT_CARE);

    campaign.setSettings(new Setting[] {universalAppSetting, geoSetting});

    // Create the operation.
    CampaignOperation operation = new CampaignOperation();
    operation.setOperand(campaign);
    operation.setOperator(Operator.ADD);

    CampaignOperation[] operations = new CampaignOperation[] {operation};

    // Add the campaign.
    CampaignReturnValue result = campaignService.mutate(operations);

    // Display the results.
    for (Campaign newCampaign : result.getValue()) {
      System.out.printf(
          "Universal app campaign with name '%s' and ID %d was added.%n",
          newCampaign.getName(), newCampaign.getId());

      // Optional: Set the campaign's location and language targeting. No other targeting
      // criteria can be used for universal app campaigns.
      setCampaignTargetingCriteria(newCampaign, adWordsServices, session);
    }
  }

  /**
   * Creates the budget for the campaign.
   *
   * @return the new budget.
   */
  private static Long createBudget(AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws RemoteException, ApiException {
    // Get the BudgetService.
    BudgetServiceInterface budgetService =
        adWordsServices.get(session, BudgetServiceInterface.class);

    // Create the campaign budget.
    Budget budget = new Budget();
    budget.setName("Interplanetary Cruise App Budget #" + System.currentTimeMillis());
    Money budgetAmount = new Money();
    budgetAmount.setMicroAmount(50000000L);
    budget.setAmount(budgetAmount);
    budget.setDeliveryMethod(BudgetBudgetDeliveryMethod.STANDARD);

    // Universal app campaigns don't support shared budgets.
    budget.setIsExplicitlyShared(false);
    BudgetOperation budgetOperation = new BudgetOperation();
    budgetOperation.setOperand(budget);
    budgetOperation.setOperator(Operator.ADD);

    // Add the budget
    Budget addedBudget = budgetService.mutate(new BudgetOperation[] {budgetOperation}).getValue(0);
    System.out.printf(
        "Budget with name '%s' and ID %d was created.%n",
        addedBudget.getName(), addedBudget.getBudgetId());
    return addedBudget.getBudgetId();
  }

  /** Sets the campaign's targeting criteria. */
  private static void setCampaignTargetingCriteria(
      Campaign campaign, AdWordsServicesInterface adWordsServices, AdWordsSession session)
      throws ApiException, RemoteException {
    // Get the CampaignCriterionService.
    CampaignCriterionServiceInterface campaignCriterionService =
        adWordsServices.get(session, CampaignCriterionServiceInterface.class);

    // Create locations. The IDs can be found in the documentation or
    // retrieved with the LocationCriterionService.
    Location california = new Location();
    california.setId(21137L);

    Location mexico = new Location();
    mexico.setId(2484L);

    // Create languages. The IDs can be found in the documentation or
    // retrieved with the ConstantDataService.
    Language english = new Language();
    english.setId(1000L);

    Language spanish = new Language();
    spanish.setId(1003L);

    List<Criterion> criteria = new ArrayList<>(Arrays.asList(california, mexico, english, spanish));

    // Create operations to add each of the criteria above.
    List<CampaignCriterionOperation> operations = new ArrayList<>();
    for (Criterion criterion : criteria) {
      CampaignCriterionOperation operation = new CampaignCriterionOperation();

      CampaignCriterion campaignCriterion = new CampaignCriterion();
      campaignCriterion.setCampaignId(campaign.getId());
      campaignCriterion.setCriterion(criterion);
      operation.setOperand(campaignCriterion);

      operation.setOperator(Operator.ADD);

      operations.add(operation);
    }

    // Set the campaign targets.
    CampaignCriterionReturnValue returnValue =
        campaignCriterionService.mutate(
            operations.toArray(new CampaignCriterionOperation[operations.size()]));

    if (returnValue != null && returnValue.getValue() != null) {
      // Display added campaign targets.
      for (CampaignCriterion campaignCriterion : returnValue.getValue()) {
        System.out.printf(
            "Campaign criteria of type '%s' and ID %d was added.%n",
            campaignCriterion.getCriterion().getCriterionType(),
            campaignCriterion.getCriterion().getId());
      }
    }
  }
}

Create a negative broad match keywords list and attach it to a campaign

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSet;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Keyword;
import com.google.api.ads.adwords.axis.v201809.cm.KeywordMatchType;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.SharedSet;
import com.google.api.ads.adwords.axis.v201809.cm.SharedSetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.SharedSetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.SharedSetType;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This example creates a shared list of negative broad match keywords, then attaches them to a
 * campaign.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class CreateAndAttachSharedKeywordSet {

  private static class CreateAndAttachSharedKeywordSetParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true)
    private Long campaignId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    CreateAndAttachSharedKeywordSetParams params = new CreateAndAttachSharedKeywordSetParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.campaignId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param campaignId the ID of the campaign that will use the shared set.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session,
      Long campaignId) throws RemoteException {
    // Get the SharedSetService.
    SharedSetServiceInterface sharedSetService =
        adWordsServices.get(session, SharedSetServiceInterface.class);

    // Keywords to include in the shared set.
    List<String> keywords = Arrays.asList("mars cruise", "mars hotels");

    // Create the shared negative keyword set.
    SharedSet sharedSet = new SharedSet();
    sharedSet.setName("Negative keyword list #" + System.currentTimeMillis());
    sharedSet.setType(SharedSetType.NEGATIVE_KEYWORDS);

    SharedSetOperation sharedSetOperation = new SharedSetOperation();
    sharedSetOperation.setOperator(Operator.ADD);
    sharedSetOperation.setOperand(sharedSet);

    // Add the shared set.
    sharedSet = sharedSetService.mutate(new SharedSetOperation[] {sharedSetOperation}).getValue(0);

    System.out.printf("Shared set with ID %d and name '%s' was successfully added.%n",
        sharedSet.getSharedSetId(), sharedSet.getName());

    // Add negative keywords to the shared set.
    List<SharedCriterionOperation> sharedCriterionOperations = new ArrayList<>();
    for (String keyword : keywords) {
      Keyword keywordCriterion = new Keyword();
      keywordCriterion.setText(keyword);
      keywordCriterion.setMatchType(KeywordMatchType.BROAD);

      SharedCriterion sharedCriterion = new SharedCriterion();
      sharedCriterion.setCriterion(keywordCriterion);
      sharedCriterion.setNegative(true);
      sharedCriterion.setSharedSetId(sharedSet.getSharedSetId());

      SharedCriterionOperation sharedCriterionOperation = new SharedCriterionOperation();
      sharedCriterionOperation.setOperator(Operator.ADD);
      sharedCriterionOperation.setOperand(sharedCriterion);

      sharedCriterionOperations.add(sharedCriterionOperation);
    }

    // Get the SharedCriterionService.
    SharedCriterionServiceInterface sharedCriterionService =
        adWordsServices.get(session, SharedCriterionServiceInterface.class);

    SharedCriterionReturnValue sharedCriterionReturnValue =
        sharedCriterionService.mutate(sharedCriterionOperations.toArray(
            new SharedCriterionOperation[sharedCriterionOperations.size()]));

    for (SharedCriterion addedCriterion : sharedCriterionReturnValue.getValue()) {
      System.out.printf("Added shared criterion ID %d with text '%s' to shared set with ID %d.%n",
          addedCriterion.getCriterion().getId(),
          ((Keyword) addedCriterion.getCriterion()).getText(), addedCriterion.getSharedSetId());
    }

    // Attach the negative keyword shared set to the campaign.
    CampaignSharedSetServiceInterface campaignSharedSetService =
        adWordsServices.get(session, CampaignSharedSetServiceInterface.class);

    CampaignSharedSet campaignSharedSet = new CampaignSharedSet();
    campaignSharedSet.setCampaignId(campaignId);
    campaignSharedSet.setSharedSetId(sharedSet.getSharedSetId());

    CampaignSharedSetOperation campaignSharedSetOperation = new CampaignSharedSetOperation();
    campaignSharedSetOperation.setOperator(Operator.ADD);
    campaignSharedSetOperation.setOperand(campaignSharedSet);

    campaignSharedSet = campaignSharedSetService.mutate(
        new CampaignSharedSetOperation[] {campaignSharedSetOperation}).getValue(0);

    System.out.printf("Shared set ID %d was attached to campaign ID %d.%n",
        campaignSharedSet.getSharedSetId(), campaignSharedSet.getCampaignId());
  }
}

Find and remove shared sets and shared set criteria

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.beust.jcommander.Parameter;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.utils.v201809.SelectorBuilder;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSet;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSetPage;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignSharedSetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Criterion;
import com.google.api.ads.adwords.axis.v201809.cm.CriterionType;
import com.google.api.ads.adwords.axis.v201809.cm.Keyword;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.Placement;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterion;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionOperation;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionPage;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.SharedCriterionServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.SharedSetType;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.selectorfields.v201809.cm.CampaignSharedSetField;
import com.google.api.ads.adwords.lib.utils.examples.ArgumentNames;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.common.lib.utils.examples.CodeSampleParams;
import com.google.api.client.auth.oauth2.Credential;
import com.google.common.base.Functions;
import com.google.common.collect.Collections2;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

/**
 * This example demonstrates how to find and remove shared sets and shared set criteria.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class FindAndRemoveCriteriaFromSharedSet {

  private static final int PAGE_SIZE = 100;
  
  private static class FindAndRemoveCriteriaFromSharedSetParams extends CodeSampleParams {
    @Parameter(names = ArgumentNames.CAMPAIGN_ID, required = true)
    private Long campaignId;
  }

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    FindAndRemoveCriteriaFromSharedSetParams params =
        new FindAndRemoveCriteriaFromSharedSetParams();
    if (!params.parseArguments(args)) {
      // Either pass the required parameters for this example on the command line, or insert them
      // into the code here. See the parameter class definition above for descriptions.
      params.campaignId = Long.parseLong("INSERT_CAMPAIGN_ID_HERE");
    }

    try {
      runExample(adWordsServices, session, params.campaignId);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param campaignId the ID of the campaign to use to find shared sets.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices, AdWordsSession session,
      Long campaignId) throws RemoteException {
    // Get the CampaignSharedSetService.
    CampaignSharedSetServiceInterface campaignSharedSetService =
        adWordsServices.get(session, CampaignSharedSetServiceInterface.class);

    // First, retrieve all shared sets associated with the campaign.
    int offset = 0;
    SelectorBuilder selectorBuilder = new SelectorBuilder()
      .fields(
          CampaignSharedSetField.SharedSetId,
          CampaignSharedSetField.CampaignId,
          CampaignSharedSetField.SharedSetName,
          CampaignSharedSetField.SharedSetType)
      .equals(CampaignSharedSetField.CampaignId, campaignId.toString())
      .in(
          CampaignSharedSetField.SharedSetType,
          SharedSetType.NEGATIVE_KEYWORDS.getValue(),
          SharedSetType.NEGATIVE_PLACEMENTS.getValue())
      .limit(PAGE_SIZE);
    
    List<Long> sharedSetIds = new ArrayList<>();
    CampaignSharedSetPage campaignSharedSetPage;
    do {
      selectorBuilder.offset(offset);
      campaignSharedSetPage = campaignSharedSetService.get(selectorBuilder.build());
      for (CampaignSharedSet campaignSharedSet : campaignSharedSetPage.getEntries()) {
        sharedSetIds.add(campaignSharedSet.getSharedSetId());
        System.out.printf("Campaign shared set ID %d and name '%s' found for campaign ID %d.%n",
            campaignSharedSet.getSharedSetId(), campaignSharedSet.getSharedSetName(),
            campaignSharedSet.getCampaignId());
      }
      offset += PAGE_SIZE;
    } while (offset < campaignSharedSetPage.getTotalNumEntries());

    if (sharedSetIds.isEmpty()) {
      System.out.printf("No shared sets found for campaign ID %d.%n", campaignId);
      return;
    }

    // Next, retrieve criterion IDs for all found shared sets.
    SharedCriterionServiceInterface sharedCriterionService =
        adWordsServices.get(session, SharedCriterionServiceInterface.class);

    // Transform shared set IDs to strings.
    String[] sharedSetIdStrings = Collections2.transform(sharedSetIds, Functions.toStringFunction())
        .toArray(new String[sharedSetIds.size()]);
    
    offset = 0;
    selectorBuilder = new SelectorBuilder()
      .fields("SharedSetId", "Id", "KeywordText", "KeywordMatchType", "PlacementUrl")
      .in("SharedSetId", sharedSetIdStrings)
      .limit(PAGE_SIZE);
    
    List<SharedCriterionOperation> removeCriterionOperations = new ArrayList<>();
    SharedCriterionPage sharedCriterionPage;
    do {
      selectorBuilder.offset(offset);
      sharedCriterionPage = sharedCriterionService.get(selectorBuilder.build());
      for (SharedCriterion sharedCriterion : sharedCriterionPage.getEntries()) {
        if (CriterionType.KEYWORD.equals(sharedCriterion.getCriterion().getType())) {
          Keyword keyword = (Keyword) sharedCriterion.getCriterion();
          System.out.printf("Shared negative keyword with ID %d and text '%s' was found.%n",
              keyword.getId(), keyword.getText());
        } else if (CriterionType.PLACEMENT.equals(sharedCriterion.getCriterion().getType())) {
          Placement placement = (Placement) sharedCriterion.getCriterion();
          System.out.printf("Shared negative placement with ID %d and URL '%s' was found.%n",
              placement.getId(), placement.getUrl());
        } else {
          System.out.printf("Shared criterion with ID %d was found.%n",
              sharedCriterion.getCriterion().getId());
        }

        // Create an operation to remove this criterion.
        SharedCriterionOperation removeCriterionOperation = new SharedCriterionOperation();
        removeCriterionOperation.setOperator(Operator.REMOVE);
        
        SharedCriterion sharedCriterionToRemove = new SharedCriterion();
        
        Criterion criterionToRemove = new Criterion();
        criterionToRemove.setId(sharedCriterion.getCriterion().getId());
        
        sharedCriterionToRemove.setCriterion(criterionToRemove);
        sharedCriterionToRemove.setSharedSetId(sharedCriterion.getSharedSetId());
        
        removeCriterionOperation.setOperand(sharedCriterionToRemove);

        removeCriterionOperations.add(removeCriterionOperation);
      }
      offset += PAGE_SIZE;
    } while (offset < sharedCriterionPage.getTotalNumEntries());

    // Finally, remove the criteria.
    if (removeCriterionOperations.isEmpty()) {
      System.out.printf("No shared criteria to remove.%n");
    } else {
      SharedCriterionReturnValue sharedCriterionReturnValue =
          sharedCriterionService.mutate(removeCriterionOperations.toArray(
              new SharedCriterionOperation[removeCriterionOperations.size()]));
      for (SharedCriterion removedCriterion : sharedCriterionReturnValue.getValue()) {
        System.out.printf(
            "Shared criterion ID %d was successfully removed from shared set ID %d.%n",
            removedCriterion.getCriterion().getId(), removedCriterion.getSharedSetId());
      }
    }
  }
}

Get ad group level bid modifiers

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.utils.v201809.SelectorBuilder;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifier;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifierPage;
import com.google.api.ads.adwords.axis.v201809.cm.AdGroupBidModifierServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.Selector;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.adwords.lib.selectorfields.v201809.cm.AdGroupBidModifierField;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;

/**
 * This example illustrates how to retrieve the first 10 ad group level bid modifiers.
 *
 * <p>Credentials and properties in {@code fromFile()} are pulled from the
 * "ads.properties" file. See README for more info.
 */
public class GetAdGroupBidModifier {

  private static final int PAGE_SIZE = 10;

  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    try {
      runExample(adWordsServices, session);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(AdWordsServicesInterface adWordsServices,
      AdWordsSession session) throws RemoteException {
    // Get the AdGroupBidModifierService.
    AdGroupBidModifierServiceInterface adGroupBidModifierService =
        adWordsServices.get(session, AdGroupBidModifierServiceInterface.class);

    // Create selector.
    Selector selector = new SelectorBuilder()
        .fields(
            AdGroupBidModifierField.CampaignId,
            AdGroupBidModifierField.AdGroupId,
            AdGroupBidModifierField.BidModifier,
            AdGroupBidModifierField.Id)
        .offset(0)
        .limit(PAGE_SIZE)
        .build();

    AdGroupBidModifierPage page = adGroupBidModifierService.get(selector);
    if (page.getEntries() != null) {
      for (AdGroupBidModifier bidModifierResult : page.getEntries()) {
        String bidModifierValue =
            bidModifierResult.getBidModifier() != null
                ? bidModifierResult.getBidModifier().toString()
                : "unset";
        System.out.printf("Campaign ID %d, AdGroup ID %d, Criterion ID %d, "
            + "has ad group level modifier: %s%n",
            bidModifierResult.getCampaignId(),
            bidModifierResult.getAdGroupId(),
            bidModifierResult.getCriterion().getId(),
            bidModifierValue);
      }
    } else {
      System.out.println("No ad group level bid modifiers were found.");
    }
  }
}

Add a portfolio bidding strategy to a campaign

// 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 adwords.axis.v201809.advancedoperations;

import static com.google.api.ads.common.lib.utils.Builder.DEFAULT_CONFIGURATION_FILENAME;

import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201809.cm.AdvertisingChannelType;
import com.google.api.ads.adwords.axis.v201809.cm.ApiError;
import com.google.api.ads.adwords.axis.v201809.cm.ApiException;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyConfiguration;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyOperation;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.BiddingStrategyServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Budget;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetBudgetDeliveryMethod;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetOperation;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.BudgetServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.Campaign;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignOperation;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignReturnValue;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201809.cm.CampaignStatus;
import com.google.api.ads.adwords.axis.v201809.cm.Money;
import com.google.api.ads.adwords.axis.v201809.cm.NetworkSetting;
import com.google.api.ads.adwords.axis.v201809.cm.Operator;
import com.google.api.ads.adwords.axis.v201809.cm.SharedBiddingStrategy;
import com.google.api.ads.adwords.axis.v201809.cm.TargetSpendBiddingScheme;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.adwords.lib.factory.AdWordsServicesInterface;
import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.conf.ConfigurationLoadException;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import java.rmi.RemoteException;
import javax.annotation.Nullable;

/**
 * This example adds a portfolio bidding strategy and uses it to construct a campaign.
 */
public class UsePortfolioBiddingStrategy {

  // Optional: If you'd like to use an existing shared budget, assign a
  //           shared budget ID here.
  private static final Long SHARED_BUDGET_ID = null; 
  
  public static void main(String[] args) {
    AdWordsSession session;
    try {
      // Generate a refreshable OAuth2 credential.
      Credential oAuth2Credential =
          new OfflineCredentials.Builder()
              .forApi(Api.ADWORDS)
              .fromFile()
              .build()
              .generateCredential();

      // Construct an AdWordsSession.
      session =
          new AdWordsSession.Builder().fromFile().withOAuth2Credential(oAuth2Credential).build();
    } catch (ConfigurationLoadException cle) {
      System.err.printf(
          "Failed to load configuration from the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, cle);
      return;
    } catch (ValidationException ve) {
      System.err.printf(
          "Invalid configuration in the %s file. Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, ve);
      return;
    } catch (OAuthException oe) {
      System.err.printf(
          "Failed to create OAuth credentials. Check OAuth settings in the %s file. "
              + "Exception: %s%n",
          DEFAULT_CONFIGURATION_FILENAME, oe);
      return;
    }

    AdWordsServicesInterface adWordsServices = AdWordsServices.getInstance();

    try {
      runExample(adWordsServices, session, SHARED_BUDGET_ID);
    } catch (ApiException apiException) {
      // ApiException is the base class for most exceptions thrown by an API request. Instances
      // of this exception have a message and a collection of ApiErrors that indicate the
      // type and underlying cause of the exception. Every exception object in the adwords.axis
      // packages will return a meaningful value from toString
      //
      // ApiException extends RemoteException, so this catch block must appear before the
      // catch block for RemoteException.
      System.err.println("Request failed due to ApiException. Underlying ApiErrors:");
      if (apiException.getErrors() != null) {
        int i = 0;
        for (ApiError apiError : apiException.getErrors()) {
          System.err.printf("  Error %d: %s%n", i++, apiError);
        }
      }
    } catch (RemoteException re) {
      System.err.printf(
          "Request failed unexpectedly due to RemoteException: %s%n", re);
    }
  }

  /**
   * Runs the example.
   *
   * @param adWordsServices the services factory.
   * @param session the session.
   * @param sharedBudgetId the ID of the shared budget to use. If null, this example will create a
   *     new shared budget.
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  public static void runExample(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      @Nullable Long sharedBudgetId)
      throws RemoteException {
    SharedBiddingStrategy portfolioBiddingStrategy =
        createBiddingStrategy(adWordsServices, session);
    if (sharedBudgetId == null) {
      Budget budget = createSharedBudget(adWordsServices, session);
      sharedBudgetId = budget.getBudgetId();
    }
    createCampaignWithBiddingStrategy(adWordsServices, session, portfolioBiddingStrategy.getId(), 
        sharedBudgetId);
  }

  /**
   * Creates the bidding strategy object.
   *
   * @param adWordsServices the user to run the example with
   * @param session the AdWordsSession
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  private static SharedBiddingStrategy createBiddingStrategy(
      AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException {
    // Get the BiddingStrategyService, which loads the required classes.
    BiddingStrategyServiceInterface biddingStrategyService =
        adWordsServices.get(session, BiddingStrategyServiceInterface.class);

    // Create a portfolio bidding strategy.
    SharedBiddingStrategy portfolioBiddingStrategy = new SharedBiddingStrategy();
    portfolioBiddingStrategy.setName("Maximize Clicks" + System.currentTimeMillis());

    TargetSpendBiddingScheme biddingScheme = new TargetSpendBiddingScheme();
    // Optionally set additional bidding scheme parameters.
    biddingScheme.setBidCeiling(new Money(null, 2000000L));
    biddingScheme.setSpendTarget(new Money(null, 20000000L));

    portfolioBiddingStrategy.setBiddingScheme(biddingScheme);

    // Create operation.
    BiddingStrategyOperation operation = new BiddingStrategyOperation();
    operation.setOperand(portfolioBiddingStrategy);
    operation.setOperator(Operator.ADD);

    BiddingStrategyOperation[] operations = new BiddingStrategyOperation[] {operation};
    BiddingStrategyReturnValue result = biddingStrategyService.mutate(operations);

    SharedBiddingStrategy newBiddingStrategy = result.getValue(0);

    System.out.printf(
        "Portfolio bidding strategy with name '%s' and ID %d of type '%s' was created.%n",
        newBiddingStrategy.getName(), newBiddingStrategy.getId(),
        newBiddingStrategy.getBiddingScheme().getBiddingSchemeType());

    return newBiddingStrategy;
  }

  /**
   * Creates an explicit budget to be used only to create the Campaign.
   *
   * @param adWordsServices the user to run the example with
   * @param session the AdWordsSession
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  private static Budget createSharedBudget(
      AdWordsServicesInterface adWordsServices, AdWordsSession session) throws RemoteException {
    // Get the BudgetService, which loads the required classes.
    BudgetServiceInterface budgetService =
        adWordsServices.get(session, BudgetServiceInterface.class);

    // Create a shared budget.
    Budget budget = new Budget();
    budget.setName("Shared Interplanetary Budget #" + System.currentTimeMillis());
    budget.setAmount(new Money(null, 50000000L));
    budget.setDeliveryMethod(BudgetBudgetDeliveryMethod.STANDARD);
    budget.setIsExplicitlyShared(true);

    BudgetOperation operation = new BudgetOperation();
    operation.setOperand(budget);
    operation.setOperator(Operator.ADD);

    BudgetOperation[] operations = new BudgetOperation[] {operation};

    // Make the mutate request.
    BudgetReturnValue result = budgetService.mutate(operations);
    Budget newBudget = result.getValue(0);

    System.out.printf("Budget with name '%s', ID %d was created.%n", newBudget.getName(),
        newBudget.getBudgetId());

    return newBudget;
  }

  /**
   * Create a Campaign with a portfolio bidding strategy.
   *
   * @param adWordsServices the user to run the example with
   * @param session the AdWordsSession
   * @param biddingStrategyId the bidding strategy id to use
   * @param sharedBudgetId the shared budget id to use
   * @throws ApiException if the API request failed with one or more service errors.
   * @throws RemoteException if the API request failed due to other errors.
   */
  private static Campaign createCampaignWithBiddingStrategy(
      AdWordsServicesInterface adWordsServices,
      AdWordsSession session,
      Long biddingStrategyId,
      Long sharedBudgetId)
      throws RemoteException {
    // Get the CampaignService, which loads the required classes.
    CampaignServiceInterface campaignService =
        adWordsServices.get(session, CampaignServiceInterface.class);

    // Create campaign.
    Campaign campaign = new Campaign();
    campaign.setName("Interplanetary Cruise #" + System.currentTimeMillis());

    // Recommendation: Set the campaign to PAUSED when creating it to prevent
    // the ads from immediately serving. Set to ENABLED once you've added
    // targeting and the ads are ready to serve.
    campaign.setStatus(CampaignStatus.PAUSED);

    // Set the budget.
    Budget budget = new Budget();
    budget.setBudgetId(sharedBudgetId);
    campaign.setBudget(budget);

    // Set bidding strategy (required).
    BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration();
    biddingStrategyConfiguration.setBiddingStrategyId(biddingStrategyId);

    campaign.setBiddingStrategyConfiguration(biddingStrategyConfiguration);

    // Set advertising channel type (required).
    campaign.setAdvertisingChannelType(AdvertisingChannelType.SEARCH);

    // Set network targeting (recommended).
    NetworkSetting networkSetting = new NetworkSetting();
    networkSetting.setTargetGoogleSearch(true);
    networkSetting.setTargetSearchNetwork(true);
    networkSetting.setTargetContentNetwork(true);
    campaign.setNetworkSetting(networkSetting);

    // Create operation.
    CampaignOperation operation = new CampaignOperation();
    operation.setOperand(campaign);
    operation.setOperator(Operator.ADD);

    CampaignReturnValue result = campaignService.mutate(new CampaignOperation[] {operation});
    Campaign newCampaign = result.getValue(0);

    System.out.printf("Campaign with name '%s', ID %d and bidding scheme ID %d was created.%n",
        newCampaign.getName(), newCampaign.getId(),
        newCampaign.getBiddingStrategyConfiguration().getBiddingStrategyId());

    return newCampaign;
  }
}