public class AdUnitFetcher extends AbstractFetcher {

  @Inject
  public AdUnitFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final InventoryServiceInterface inventoryService =
        dfpServices.get(session, InventoryServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return inventoryService.getAdUnitsByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class CompanyFetcher extends AbstractFetcher {

  @Inject
  public CompanyFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final CompanyServiceInterface companyService =
        dfpServices.get(session, CompanyServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return companyService.getCompaniesByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class CreativeFetcher extends AbstractFetcher {

  @Inject
  public CreativeFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final CreativeServiceInterface creativeService =
        dfpServices.get(session, CreativeServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return creativeService.getCreativesByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class CreativeTemplateFetcher extends AbstractFetcher {

  @Inject
  public CreativeTemplateFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final CreativeTemplateServiceInterface creativeTemplateService =
        dfpServices.get(session, CreativeTemplateServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return creativeTemplateService.getCreativeTemplatesByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class CustomTargetingKeyAndValueFetcher extends AbstractFetcher {

  @Inject
  public CustomTargetingKeyAndValueFetcher(
      DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    final CustomTargetingServiceInterface customTargetingService =
        dfpServices.get(session, CustomTargetingServiceInterface.class);

    // Create the custom targeting key page fetcher.
    PageFetcher customTargetingKeyPageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return customTargetingService.getCustomTargetingKeysByStatement(statement);
      }
    };

    // Create the custom targeting value page fetcher.
    PageFetcher customTargetingValuePageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return customTargetingService.getCustomTargetingValuesByStatement(statement);
      }
    };

    // Create all fetcher that gets all custom targeting values.
    AllSingleEntityFetcher customTargetingValueAllFetcher = new AllSingleEntityFetcher(
        customTargetingValuePageFetcher, channels, channelKey, tag + "-value", requestId);

    // Fetch all custom targeting keys and nested values.
    new AllNestedFetcher(
        customTargetingKeyPageFetcher, customTargetingValueAllFetcher, channels, channelKey, tag,
        requestId).fetchAll("WHERE customTargetingKeyId = ");
  }
} public class CustomTargetingKeyFetcher extends AbstractFetcher {

  @Inject
  public CustomTargetingKeyFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final CustomTargetingServiceInterface customTargetingService =
        dfpServices.get(session, CustomTargetingServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return customTargetingService.getCustomTargetingKeysByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class CustomTargetingValueFetcher extends AbstractFetcher {

  @Inject
  public CustomTargetingValueFetcher(
      DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final CustomTargetingServiceInterface customTargetingService =
        dfpServices.get(session, CustomTargetingServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return customTargetingService.getCustomTargetingValuesByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public final class FetchService {

  protected final Logger log = Logger.getLogger(this.getClass().getName());
  protected final Channels channels;
  protected final Sessions sessions;

  /**
   * Construct the fetch service.
   * @param channels used for Channel API communication
   * @param sessions used to create a DFP session
   */
  @Inject
  public FetchService(Channels channels, Sessions sessions) {
    this.channels = channels;
    this.sessions = sessions;
  }

  /**
   * Fetch API objects on the user's network.
   *
   * @param fetcher handles API object fetching
   * @param filterText the PQL syntax filter text to filter objects by
   * @param channelKey the key to send a message via the Channel AP
   * @param networkCode the user's network code
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param userId App Engine assigned user ID
   * @throws ServiceException if session object cannot be obtained
   */
  public void fetch(Fetcher fetcher, String filterText, String channelKey,
      String networkCode, String tag, String requestId, String userId) throws ServiceException {
    Preconditions.checkNotNull(fetcher);
    DfpSession session = getSession(channelKey, networkCode, tag, requestId, userId);
    fetcher.fetch(filterText, channelKey, tag, requestId, session);
  }

  /**
   * Gets a DFP session or sends a channel error message if it cannot be done.
   *
   * @param channelKey the key to send a message via the Channel API
   * @param networkCode the user's network code
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param userId App Engine assigned user ID
   * @return a DFP session
   * @throws ServiceException if session object cannot be obtained
   */
  private DfpSession getSession(String channelKey, String networkCode, String tag, String requestId,
      String userId) throws ServiceException {
    try {
      return sessions.get(networkCode, userId);
    } catch (ValidationException e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
      throw new ServiceException("Unable to acquire session object", e);
    } catch (CredentialException e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
      throw new ServiceException("Unable to acquire credential", e);
    }
  }

} public interface Fetcher {

  /**
   * Fetch API objects filtered by the filterText with the given session and outputs to the channel.
   *
   * @param filterText the PQL syntax filter text to filter objects by
   * @param channelKey the key to send a message via the Channel API
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param session a DFP session to make API calls with
   */
  void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session);
} public class FetcherFactory {

  private final Map<String, Fetcher> fetchers;

  @Inject
  public FetcherFactory(Map<String, Fetcher> fetchers) {
    this.fetchers = fetchers;
  }

  /**
   * Returns a fetcher for an API object.
   *
   * @param tag the panel to return results to
   * @param typeOverride determines the type of object to return for panels with multiple types
   * @return an API object fetcher
   * @throws IllegalArgumentException if a fetcher cannot be found
   */
  public Fetcher getInstance(String tag, String typeOverride) {
    Preconditions.checkNotNull(tag);
    Preconditions.checkNotNull(typeOverride);

    if (tag.equals(DfpTags.ORDERS)) {
      if (typeOverride.equals(DfpTypeOverrides.ORDERS)) {
        return fetchers.get(DfpTags.ORDERS);
      } else if (typeOverride.equals(DfpTypeOverrides.LINE_ITEMS)) {
        return fetchers.get(DfpTags.LINE_ITEMS);
      } else {
        return fetchers.get(DfpTags.ORDERS_LINE_ITEMS);
      }
    } else if (tag.equals(DfpTags.CUSTOM_TARGETING)) {
      if (typeOverride.equals(DfpTypeOverrides.KEYS)) {
        return fetchers.get(DfpTags.CUSTOM_TARGETING_KEYS);
      } else if (typeOverride.equals(DfpTypeOverrides.VALUES)) {
        return fetchers.get(DfpTags.CUSTOM_TARGETING_VALUES);
      } else {
        return fetchers.get(DfpTags.CUSTOM_TARGETING);
      }
    } else {
      Fetcher fetcher = fetchers.get(tag);
      if (fetcher != null) {
        return fetcher;
      } else {
        throw new IllegalArgumentException("Tag does not have a matching fetcher.");
      }
    }
  }
} public class LineItemCreativeAssociationFetcher extends AbstractFetcher {

  @Inject
  public LineItemCreativeAssociationFetcher(
      DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final LineItemCreativeAssociationServiceInterface lineItemCreativeAssociationService =
        dfpServices.get(session, LineItemCreativeAssociationServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return lineItemCreativeAssociationService.getLineItemCreativeAssociationsByStatement(
            statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class LineItemFetcher extends AbstractFetcher {

  @Inject
  public LineItemFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final LineItemServiceInterface lineItemService =
        dfpServices.get(session, LineItemServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return lineItemService.getLineItemsByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class NetworkFetcher extends AbstractFetcher {

  @Inject
  public NetworkFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    try {
      // Create the service.
      NetworkServiceInterface networkService =
          dfpServices.get(session, NetworkServiceInterface.class);

      // Make the request to get networks.
      List<Network> networks = networkService.getAllNetworks();

      // Return results through the channel.
      channels.sendObjects(channelKey, networks, tag, requestId);
    } catch (ApiException_Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
    } catch (Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
      log.warning("Error:" + e.getMessage());
    }
  }
} public class OrderFetcher extends AbstractFetcher {

  @Inject
  public OrderFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final OrderServiceInterface orderService =
        dfpServices.get(session, OrderServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return orderService.getOrdersByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public final class OrderLineItemFetcher extends AbstractFetcher {

  @Inject
  public OrderLineItemFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    OrderServiceInterface orderService =
        dfpServices.get(session, OrderServiceInterface.class);
    LineItemServiceInterface lineItemService =
        dfpServices.get(session, LineItemServiceInterface.class);
    fetch(filterText, channelKey, tag, requestId, orderService, lineItemService);
  }

  /**
   * Fetch orders and the nested line items.
   *
   * @param filterText the PQL syntax filter text to filter objects by
   * @param channelKey the key to send a message via the Channel API
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param orderService used to fetch orders
   * @param lineItemService used to fetch line items
   */
  @VisibleForTesting
  void fetch(String filterText, String channelKey, String tag, String requestId,
      final OrderServiceInterface orderService, final LineItemServiceInterface lineItemService) {
    // Create the order page fetcher.
    PageFetcher orderPageFetcher = new PageFetcher() {
      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return orderService.getOrdersByStatement(statement);
      }
    };

    // Create the line item page fetcher.
    PageFetcher lineItemPageFetcher = new PageFetcher() {
      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return lineItemService.getLineItemsByStatement(statement);
      }
    };

    // Create all fetcher that gets all line items.
    AllSingleEntityFetcher lineItemAllFetcher = new AllSingleEntityFetcher(lineItemPageFetcher,
        channels, channelKey, tag + "-li", requestId);

    // Fetch all orders and nested line items.
    new AllNestedFetcher(orderPageFetcher, lineItemAllFetcher, channels, channelKey, tag, requestId)
        .fetchAll("WHERE orderId = ");
  }
} public class PlacementFetcher extends AbstractFetcher {

  @Inject
  public PlacementFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    fetch(filterText, channelKey, tag, requestId,
        dfpServices.get(session, PlacementServiceInterface.class));
  }

  /**
   * Fetch placements.
   *
   * @param filterText the PQL syntax filter text to filter objects by
   * @param channelKey the key to send a message via the Channel API
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param placementService used to fetch placements
   */
  public void fetch(String filterText, String channelKey, String tag, String requestId,
      final PlacementServiceInterface placementService) {
    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return placementService.getPlacementsByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class PublisherQueryLanguageFetcher extends AbstractFetcher {

  @Inject
  public PublisherQueryLanguageFetcher(
      DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    fetch(filterText, channelKey, tag, requestId,
        dfpServices.get(session, PublisherQueryLanguageServiceInterface.class));
  }

  /**
   * Fetch publisher query language table results.
   *
   * @param filterText the PQL syntax filter text to filter objects by
   * @param channelKey the key to send a message via the Channel API
   * @param tag identifies that objects that are sent via the channel
   * @param requestId identifies the incoming data request
   * @param pqlService used to fetch tables
   */
  @VisibleForTesting
  void fetch(String filterText, String channelKey, String tag, String requestId,
      final PublisherQueryLanguageServiceInterface pqlService) {
    try {
      // Create statement with filter.
      Statement filterStatement = new Statement();
      filterStatement.setQuery(filterText);

      // Make select request.
      ResultSet resultSet = pqlService.select(filterStatement);
      List<String[]> stringResult = Pql.resultSetToStringArrayList(resultSet);

      channels.sendObjects(channelKey, stringResult, tag, requestId);
    } catch (ApiException_Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
    } catch (Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
      log.log(Level.SEVERE, "Error fetching objects.", e);
    }
  }
} public class RoleFetcher extends AbstractFetcher {

  @Inject
  public RoleFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    try {
      // Create the service.
      UserServiceInterface userService = dfpServices.get(session, UserServiceInterface.class);

      // Make request for roles.
      List<Role> roles = userService.getAllRoles();

      // Return results through the channel.
      channels.sendObjects(channelKey, roles, tag, requestId);
    } catch (ApiException_Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
    } catch (Exception e) {
      channels.sendErrorChannelMessage(channelKey, tag, requestId, e.getMessage());
      log.warning("Error:" + e.getMessage());
    }
  }
} public class UserFetcher extends AbstractFetcher {

  @Inject
  public UserFetcher(DfpServices dfpServices, Channels channels) {
    super(dfpServices, channels);
  }

  public void fetch(String filterText, String channelKey, String tag, String requestId,
      DfpSession session) {
    // Create the service.
    final UserServiceInterface userService = dfpServices.get(session, UserServiceInterface.class);

    // Create the page fetcher.
    PageFetcher pageFetcher = new PageFetcher() {

      public Object getByStatement(Statement statement) throws ApiException_Exception {
        return userService.getUsersByStatement(statement);
      }
    };
    // Fetch the objects.
    fetchObjects(filterText, channelKey, tag, requestId, pageFetcher);
  }
} public class GsonModule extends AbstractModule {
  @Override
  protected void configure() {
    bind(Gson.class).toInstance(new GsonBuilder().serializeNulls().create());
  }
} public class AuthorizationCodeFlowFactory {

  private final CredentialStore credentialStore;
  private final HttpTransport httpTransport;
  private final JsonFactory jsonFactory;
  private final String clientId;
  private final String clientSecret;
  private final String scope;

  @Inject
  public AuthorizationCodeFlowFactory(CredentialStore credentialStore,
      JsonFactory jsonFactory,
      HttpTransport httpTransport,
      @Named("clientId") String clientId,
      @Named("clientSecret") String clientSecret,
      @Named("scope") String scope) {
    this.credentialStore = credentialStore;
    this.httpTransport = httpTransport;
    this.jsonFactory = jsonFactory;
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.scope = scope;
  }

  /**
   * Returns a fetcher for an API object.
   *
   * @return a Google authorization code flow
   */
  public GoogleAuthorizationCodeFlow getInstance() {
    Preconditions.checkNotNull(clientId);
    Preconditions.checkNotNull(clientSecret);
    return new GoogleAuthorizationCodeFlow.Builder(
        httpTransport,
        jsonFactory,
        clientId,
        clientSecret,
        Lists.newArrayList(scope))
        .setCredentialStore(credentialStore)
        .setApprovalPrompt("force")
        .setAccessType("offline")
        .build();
  }

} public class CredentialFactory {

  private final String clientId;
  private final String clientSecret;
  private final CredentialStore credentialStore;
  private final HttpTransport httpTransport;
  private final JsonFactory jsonFactory;

  @Inject
  public CredentialFactory(CredentialStore credentialStore, HttpTransport httpTransport,
      JsonFactory jsonFactory, @Named("clientId") String clientId,
      @Named("clientSecret") String clientSecret) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.credentialStore = credentialStore;
    this.httpTransport = httpTransport;
    this.jsonFactory = jsonFactory;
  }

  /**
   * Fetch the OAuth2 credential from the App Engine Datastore.
   *
   * @param userId the App Engine assigned user ID
   * @return the oAuth2 credential
   * @throws CredentialException if the credential cannot be obtained
   */
  public Credential getInstance(String userId) throws CredentialException {
    Preconditions.checkNotNull(clientId);
    Preconditions.checkNotNull(clientSecret);
    GoogleCredential credential = new GoogleCredential.Builder()
        .setJsonFactory(jsonFactory)
        .setTransport(httpTransport)
        .setClientSecrets(clientId, clientSecret)
        .build();
    try {
      credentialStore.load(userId, credential);
      try {
        credential.refreshToken();
      } catch (IOException e) {
        credentialStore.delete(userId, credential);
        throw new CredentialException("Credential cannot be refreshed.", e);
      }
    } catch (IOException e) {
      throw new CredentialException("Credential cannot be loaded.", e);
    }
    return credential;
  }
} @Singleton
@SuppressWarnings("serial")
public class CreateNetworkServlet extends AuthServlet {

  private final Networks networks;
  private final UserService userService;

  /**
   * Constructor.
   *
   * @param networks used to create networks
   * @param userService the App Engine service for user management
   * @param authorizationCodeFlowFactory used to get an OAuth2 flow
   * @param redirectUrl where to direct the user once authorization is done
   */
  @Inject
  public CreateNetworkServlet(Networks networks, UserService userService,
      AuthorizationCodeFlowFactory authorizationCodeFlowFactory,
      @Named("redirectUrl") String redirectUrl) {
    super(authorizationCodeFlowFactory, redirectUrl);
    this.networks = networks;
    this.userService = userService;
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    ServletContext servletContext = getServletContext();
    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/newNetwork.jsp");
    requestDispatcher.forward(req, resp);
  }

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    ServletContext servletContext = getServletContext();
    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/newNetwork.jsp");
    if (req.getParameter("createNetwork") != null) {
      try {
        Network newNetwork = networks.make(userService.getCurrentUser().getUserId());
        resp.sendRedirect("/index?newNetworkCode=" + newNetwork.getNetworkCode());
        return;
      } catch (ApiException_Exception e) {
        req.setAttribute("error", true);
      } catch (ValidationException e) {
        req.setAttribute("error", true);
      } catch (CredentialException e) {
        resp.sendRedirect("/");
        return;
      }
    }
    requestDispatcher.forward(req, resp);
  }
} @Singleton
public class DeniedServlet extends HttpServlet {

  static final Logger log = Logger.getLogger(DeniedServlet.class.getName());

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    resp.sendRedirect("/denied.jsp");
  }
} @Singleton
public class DfpServlet extends HttpServlet {

  static final Logger log = Logger.getLogger(DfpServlet.class.getName());
  private final FetcherFactory fetcherFactory;
  private final FetchService fetchService;

  @Inject
  public DfpServlet(FetcherFactory fetcherFactory, FetchService fetchService) {
    this.fetcherFactory = fetcherFactory;
    this.fetchService = fetchService;
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) {
    String filterText = req.getParameter("filterText");
    String channelKey = req.getParameter("key");
    String networkCode = req.getParameter("networkCode");
    String tag = req.getParameter("tag");
    String typeOverride = req.getParameter("typeOverride");
    String userId = req.getParameter("userId");
    String requestId = req.getParameter("reqId");
    try {
      Fetcher fetcher = fetcherFactory.getInstance(tag, typeOverride);
        fetchService.fetch(fetcher, filterText, channelKey, networkCode, tag, requestId, userId);
    } catch (IllegalArgumentException e) {
      log.log(Level.WARNING, "Fetcher cannot be found.", e);
    } catch (ServiceException e) {
      log.log(Level.SEVERE, "Error fetching with service.", e);
    }
  }
} @Singleton
@SuppressWarnings("serial")
public class IndexServlet extends AuthServlet {

  // TODO(user): Look for ways to use server filter to parse for network code.
  private static final Pattern NETWORK_CODE_PATTERN = Pattern.compile("/(\\d+)");

  static final Logger log = Logger.getLogger(IndexServlet.class.getName());
  private final Networks networks;
  private final ChannelService channelService;
  private final MemcacheService memcacheService;
  private final UserService userService;
  private final int expirationDelta;

  /**
   * Constructor.
   *
   * @param channelService service for handling channel communication
   * @param networks used to get a list of networks
   * @param userService the App Engine service for user management
   * @param memcacheService the App Engine caching service
   * @param expirationDelta the cache expiration delta in seconds
   * @param authorizationCodeFlowFactory used to get an OAuth2 flow
   * @param redirectUrl where to direct the user once authorization is done
   */
  @Inject
  public IndexServlet(ChannelService channelService,
      Networks networks,
      UserService userService,
      MemcacheService memcacheService,
      @Named("expirationDelta") int expirationDelta,
      AuthorizationCodeFlowFactory authorizationCodeFlowFactory,
      @Named("redirectUrl") String redirectUrl) {
    super(authorizationCodeFlowFactory, redirectUrl);
    this.channelService = channelService;
    this.networks = networks;
    this.memcacheService = memcacheService;
    this.userService = userService;
    this.expirationDelta = expirationDelta;
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    String userId = userService.getCurrentUser().getUserId();
    ServletContext servletContext = getServletContext();
    RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/index.jsp");
    @SuppressWarnings("unchecked") // Casting cached data into map.
    Map<String, String> networkMap = (Map<String, String>) memcacheService.get(userId);
    if (networkMap != null) {
      req.setAttribute("networks", networkMap);
    } else {
      try {
        List<Network> testNetworks = networks.get(userId);
        if (!testNetworks.isEmpty()) {
          Map<String, String> fetchedNetworkMap = getNetworkCodeDisplayNameMap(testNetworks);
          req.setAttribute("networks", fetchedNetworkMap);
          memcacheService.put(
              userId, fetchedNetworkMap, Expiration.byDeltaSeconds(expirationDelta));
          networkMap = fetchedNetworkMap;
        } else {
          resp.sendRedirect("/newnetwork");
          return;
        }
      } catch (ApiException_Exception e) {
        req.setAttribute("error", e.getMessage());
        requestDispatcher.forward(req, resp);
        return;
      } catch (ValidationException e) {
        req.setAttribute("error", e.getMessage());
        requestDispatcher.forward(req, resp);
        return;
      } catch (CredentialException e) {
        resp.sendRedirect("/");
        return;
      }
    }

    String networkCode = getNetworkCode(req);

      // Redirect if the user only belongs to one network.
      if (networkCode == null && networkMap.size() == 1) {
        resp.sendRedirect(getNetworkRedirectUrl(req, networkMap));
        return;
      }

    req.setAttribute("network_code", networkCode);


    req.setAttribute("logout_url", userService.createLogoutURL("/"));
    req.setAttribute("user", userService.getCurrentUser().getEmail());
    req.setAttribute("new_network_code", req.getParameter("newNetworkCode"));
    String token = channelService.createChannel(userId);
    req.setAttribute("channel_token", token);
    requestDispatcher.forward(req, resp);
  }

  /**
   * @param req The servlet request
   * @param networkMap a map of network codes to network names
   * @return the redirect url
   */
  private String getNetworkRedirectUrl(HttpServletRequest req, Map<String, String> networkMap) {
    String redirectNetworkCode = networkMap.entrySet().iterator().next().getKey();
    StringBuilder builder = new StringBuilder().append("/").append(redirectNetworkCode);
    if (req.getParameter("newNetworkCode") != null) {
      builder.append("?newNetworkCode=").append(req.getParameter("newNetworkCode"));
    }
    return builder.toString();
  }

  /**
   * Gets a network code from the request URI. Returns null if not found.
   *
   * @param req The servlet request
   * @return the network code or null if not found
   */
  private String getNetworkCode(HttpServletRequest req) {
    String uri = req.getRequestURI();
    Matcher matcher = NETWORK_CODE_PATTERN.matcher(uri);
    return matcher.matches() ? matcher.group(1) : null;
  }

  /**
   * Produce a map of network code to display name.
   *
   * @param networks List of networks.
   * @return a map of network codes to network names.
   */
  private Map<String, String> getNetworkCodeDisplayNameMap(List<Network> networks) {
    Map<String, String> networkCodeDisplayNameMap = Maps.newHashMap();
    for (Network network : networks) {
      networkCodeDisplayNameMap.put(network.getNetworkCode(), network.getDisplayName());
    }
    return networkCodeDisplayNameMap;
  }
} @Singleton
public class OAuth2CallbackServlet extends AbstractAppEngineAuthorizationCodeCallbackServlet {

  private static final Logger LOG = Logger.getLogger(OAuth2CallbackServlet.class.getName());
  private final AuthorizationCodeFlowFactory authorizationCodeFlowFactory;
  private final String redirectUrl;

  @Inject
  public OAuth2CallbackServlet(AuthorizationCodeFlowFactory authorizationCodeFlowFactory,
      @Named("redirectUrl") String redirectUrl) {
    this.authorizationCodeFlowFactory = authorizationCodeFlowFactory;
    this.redirectUrl = redirectUrl;
  }

  @Override
  protected AuthorizationCodeFlow initializeFlow() {
    return authorizationCodeFlowFactory.getInstance();
  }

  @Override
  protected String getRedirectUri(HttpServletRequest req) {
    GenericUrl url = new GenericUrl(req.getRequestURL().toString());
    url.setRawPath(redirectUrl);
    return url.build();
  }

  @Override
  protected void onSuccess(
      HttpServletRequest request, HttpServletResponse response, Credential credential) {
    try {
      response.sendRedirect("/dfp");
    } catch (IOException e) {
      LOG.warning("Cannot redirect on authorization success.");
    }
  }

  @Override
  protected void onError(HttpServletRequest request, HttpServletResponse response,
      AuthorizationCodeResponseUrl errorResponse) {
    try {
      response.sendRedirect("/denied");
    } catch (IOException e) {
      LOG.warning("Cannot redirect on authorization error.");
    }
  }
} @Singleton
@SuppressWarnings("serial")
public class TaskDispatchServlet extends HttpServlet {

  private final UserService userService;

  /**
   * Constructor.
   *
   * @param userService service to get the App Engine user entity
   */
  @Inject
  public TaskDispatchServlet(UserService userService) {
    this.userService = userService;
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String channelKey = getChannelKey();
    String filterText = req.getParameter("filterText");
    filterText = (filterText == null) ? "" : filterText;
    String tag = req.getParameter("tag");
    String requestId = req.getParameter("reqId");
    String userId = userService.getCurrentUser().getUserId();

    Queue queue = QueueFactory.getDefaultQueue();
    TaskOptions taskOptions = withUrl("/fetch")
        .param("displayStyle", req.getParameter("displayStyle"))
        .param("filterText", filterText)
        .param("key", channelKey)
        .param("networkCode", req.getParameter("networkCode"))
        .param("userId", userId)
        .param("tag", tag)
        .param("reqId", requestId)
        .param("typeOverride", req.getParameter("typeOverride"));

    queue.add(taskOptions.method(Method.GET));
    resp.getWriter().print(channelKey);
  }

  /**
   * Gets the channel key.
   */
  private String getChannelKey() {
    return userService.getCurrentUser().getUserId();
  }
}
import com.google.api.ads.dfp.appengine.fetcher.AdUnitFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CompanyFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CreativeFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CreativeTemplateFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CustomTargetingKeyAndValueFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CustomTargetingKeyFetcher;
import com.google.api.ads.dfp.appengine.fetcher.CustomTargetingValueFetcher;
import com.google.api.ads.dfp.appengine.fetcher.FetchService;
import com.google.api.ads.dfp.appengine.fetcher.Fetcher;
import com.google.api.ads.dfp.appengine.fetcher.FetcherFactory;
import com.google.api.ads.dfp.appengine.fetcher.LineItemCreativeAssociationFetcher;
import com.google.api.ads.dfp.appengine.fetcher.LineItemFetcher;
import com.google.api.ads.dfp.appengine.fetcher.NetworkFetcher;
import com.google.api.ads.dfp.appengine.fetcher.OrderFetcher;
import com.google.api.ads.dfp.appengine.fetcher.OrderLineItemFetcher;
import com.google.api.ads.dfp.appengine.fetcher.PlacementFetcher;
import com.google.api.ads.dfp.appengine.fetcher.PublisherQueryLanguageFetcher;
import com.google.api.ads.dfp.appengine.fetcher.RoleFetcher;
import com.google.api.ads.dfp.appengine.fetcher.UserFetcher;
import com.google.api.ads.dfp.appengine.json.GsonModule;
import com.google.api.ads.dfp.appengine.oauth.AuthorizationCodeFlowFactory;
import com.google.api.ads.dfp.appengine.oauth.CredentialFactory;
import com.google.api.ads.dfp.appengine.servlet.CreateNetworkServlet;
import com.google.api.ads.dfp.appengine.servlet.DeniedServlet;
import com.google.api.ads.dfp.appengine.servlet.DfpServlet;
import com.google.api.ads.dfp.appengine.servlet.IndexServlet;
import com.google.api.ads.dfp.appengine.servlet.OAuth2CallbackServlet;
import com.google.api.ads.dfp.appengine.servlet.TaskDispatchServlet;
import com.google.api.ads.dfp.jaxws.factory.DfpServices;
import com.google.api.client.auth.oauth2.CredentialStore;
import com.google.api.client.extensions.appengine.auth.oauth2.AppEngineCredentialStore;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.appengine.api.channel.ChannelService;
import com.google.appengine.api.channel.ChannelServiceFactory;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.apphosting.api.ApiProxy;
import com.google.inject.Provider;
import com.google.inject.multibindings.MapBinder;
import com.google.inject.name.Names;
import com.google.inject.servlet.ServletModule;
import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.ads.dfp.appengine;



/**
 * Configures the servlet bindings.
 *
 * @author Jeff Sham
 */
public class PlaygroundServletModule extends ServletModule {

  static final Logger log = Logger.getLogger(PlaygroundServletModule.class.getName());

  /**
   * If you do not have a client ID or secret, please create one in the API console:
   * https://console.developers.google.com
   */
  private static final String CLIENT_ID = System.getProperty("dfp.appengine.clientId");
  private static final String CLIENT_SECRET = System.getProperty("dfp.appengine.clientSecret");
  private static final String SCOPE = "https://www.google.com/apis/ads/publisher";

  /**
   * The redirect URL must be registered in the API console: https://code.google.com/apis/console/
   * This is so that once the user has authorized your app, they are redirected back to your app.
   */
  private static final String REDIRECT_URL = "/oauth2callback";

  /**
   * The absolute path to the playground properties file.
   */
  private static final String PROPERTIES_PATH = "/WEB-INF/dfp-playground.properties";

  /**
   * The property name for the playground version.
   */
  private static final String VERSION_PROPERTY = "version";

  /**
   * String for an unknown version.
   */
  private static final String UNKNOWN_VERSION = "unknown";

  /**
   * The number of seconds to keep a user's networks in memcache.
   */
  private static final int EXPIRATION_DELTA = 60 * 60;

  @Override
  protected void configureServlets() {
    super.configureServlets();

    serve("/").with(IndexServlet.class);
    serve("/denied").with(DeniedServlet.class);
    serve("/dfp").with(IndexServlet.class);
    serveRegex("/[0-9]+").with(IndexServlet.class);
    serve("/fetch").with(DfpServlet.class);
    serve("/get").with(TaskDispatchServlet.class);
    serve("/newnetwork").with(CreateNetworkServlet.class);
    serve(REDIRECT_URL).with(OAuth2CallbackServlet.class);

    MapBinder<String, Fetcher> mapbinder =
        MapBinder.newMapBinder(binder(), String.class, Fetcher.class);
    mapbinder.addBinding(DfpTags.AD_UNITS).to(AdUnitFetcher.class);
    mapbinder.addBinding(DfpTags.COMPANIES).to(CompanyFetcher.class);
    mapbinder.addBinding(DfpTags.CREATIVES).to(CreativeFetcher.class);
    mapbinder.addBinding(DfpTags.CREATIVE_TEMPLATES).to(CreativeTemplateFetcher.class);
    mapbinder.addBinding(DfpTags.CUSTOM_TARGETING_KEYS).to(CustomTargetingKeyFetcher.class);
    mapbinder.addBinding(DfpTags.CUSTOM_TARGETING).to(CustomTargetingKeyAndValueFetcher.class);
    mapbinder.addBinding(DfpTags.CUSTOM_TARGETING_VALUES).to(CustomTargetingValueFetcher.class);
    mapbinder.addBinding(DfpTags.LINE_ITEM_CREATIVE_ASSOCIATIONS)
        .to(LineItemCreativeAssociationFetcher.class);
    mapbinder.addBinding(DfpTags.LINE_ITEMS).to(LineItemFetcher.class);
    mapbinder.addBinding(DfpTags.NETWORKS).to(NetworkFetcher.class);
    mapbinder.addBinding(DfpTags.ORDERS).to(OrderFetcher.class);
    mapbinder.addBinding(DfpTags.ORDERS_LINE_ITEMS).to(OrderLineItemFetcher.class);
    mapbinder.addBinding(DfpTags.PLACEMENTS).to(PlacementFetcher.class);
    mapbinder.addBinding(DfpTags.PUBLISHER_QUERY_LANGUAGE).to(PublisherQueryLanguageFetcher.class);
    mapbinder.addBinding(DfpTags.ROLES).to(RoleFetcher.class);
    mapbinder.addBinding(DfpTags.USERS).to(UserFetcher.class);

    // The application name reported to the DFP API. Defaulted to the App Engine Unique ID.
    bind(String.class)
        .annotatedWith(Names.named("applicationName")).toProvider(new Provider<String>() {
          public String get() {
            String version = UNKNOWN_VERSION;
            Properties properties = new Properties();
            try {
              properties.load(getServletContext().getResourceAsStream(PROPERTIES_PATH));
              version = properties.getProperty(VERSION_PROPERTY);
            } catch (IOException e) {
              log.log(Level.SEVERE, "Cannot fetch file from " + PROPERTIES_PATH, e);
            }
            return ApiProxy.getCurrentEnvironment().getAppId() + "/" + version;
          }
        });

    if (CLIENT_ID == null || CLIENT_ID.equals("INSERT_CLIENT_ID_HERE")
        || CLIENT_SECRET == null || CLIENT_SECRET.equals("INSERT_CLIENT_SECRET_HERE")) {
      throw new IllegalArgumentException(
          "Please input your client IDs or secret in your WEB-INF/appengine-web.xml file.");
    }

    bindConstant().annotatedWith(Names.named("clientId")).to(CLIENT_ID);
    bindConstant().annotatedWith(Names.named("clientSecret")).to(CLIENT_SECRET);
    bindConstant().annotatedWith(Names.named("scope")).to(SCOPE);
    bindConstant().annotatedWith(Names.named("redirectUrl")).to(REDIRECT_URL);
    bindConstant().annotatedWith(Names.named("expirationDelta")).to(EXPIRATION_DELTA);

    bind(FetchService.class);