// Copyright 2011 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.lib.client; import com.google.api.ads.common.lib.auth.OAuth2Compatible; import com.google.api.ads.common.lib.client.AdsSession; import com.google.api.ads.common.lib.conf.ConfigurationHelper; import com.google.api.ads.common.lib.conf.ConfigurationLoadException; import com.google.api.ads.common.lib.exception.ValidationException; import com.google.api.client.auth.oauth2.Credential; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import org.apache.commons.configuration.Configuration; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import javax.annotation.concurrent.ThreadSafe; /** * A {@code DfpSession} represents a single session of DFP use. * * <p> * Implementation is not thread-safe. * </p> */ public class DfpSession implements AdsSession, OAuth2Compatible { private String networkCode; private Credential oAuth2Credential; private final String applicationName; private final String endpoint; public static final String DEFAULT_ENDPOINT = "https://ads.google.com/"; private static final String DEFAULT_APPLICATION_NAME = "INSERT_APPLICATION_NAME_HERE"; /** * Private constructor. * * @param builder the DfpSession builder */ private DfpSession(Builder builder) { this.applicationName = builder.applicationName; this.endpoint = builder.endpoint; this.networkCode = builder.networkCode; this.oAuth2Credential = builder.oAuth2Credential; } /** * Gets the application name. */ public String getApplicationName() { return applicationName; } /** * Gets the OAuth2 credentials. */ @Override public Credential getOAuth2Credential() { return oAuth2Credential; } /** * Sets the OAuth2 credential. Any other authentication credentials on the * session will be removed. */ public void setOAuth2Credential(Credential oAuth2Credential) { Preconditions.checkNotNull(oAuth2Credential, "oAuth2Credential cannot be null."); clearAuthentication(); this.oAuth2Credential = oAuth2Credential; } /** * Gets the endpoint. */ @Override public String getEndpoint() { return endpoint; } /** * Gets the network code. */ public String getNetworkCode() { return networkCode; } /** * Sets the network code. */ public void setNetworkCode(String networkCode) { this.networkCode = networkCode; } /** * Clears all the authentication credentials from this session. */ private void clearAuthentication() { oAuth2Credential = null; } /** * Returns a new {@link Builder} with all settings copied from this session. This is <em>not</em> * thread-safe unless this session is an {@link ImmutableDfpSession}. */ public Builder newBuilder() { return new Builder(this); } /** * Immutable, thread-safe implementation of DfpSession. */ @ThreadSafe public static final class ImmutableDfpSession extends DfpSession { private ImmutableDfpSession(Builder builder) { super(builder); } private void throwUnsupportedOperationException(String attributeName) { throw new UnsupportedOperationException( String.format( "Cannot set %s. ImmutableDfpSession is immutable.", attributeName)); } @Override public void setOAuth2Credential(Credential oAuth2Credential) { throwUnsupportedOperationException("oAuth2Credential"); } @Override public void setNetworkCode(String networkCode) { throwUnsupportedOperationException("networkCode"); } } /** * Builder for {@code DfpSession}. * * <p> * Implementation is not thread-safe. * </p> */ public static class Builder implements com.google.api.ads.common.lib.utils.Builder<DfpSession> { private String applicationName; private String endpoint; private String networkCode; private Credential oAuth2Credential; private final ConfigurationHelper configHelper; /** * Constructs an empty builder. To construct a builder initialized to the settings of * an existing {@link DfpSession}, use {@link DfpSession#newBuilder()} instead. */ public Builder() { this.configHelper = new ConfigurationHelper(); } private Builder(DfpSession dfpSessionToClone) { this(); this.applicationName = dfpSessionToClone.getApplicationName(); this.endpoint = dfpSessionToClone.getEndpoint(); this.networkCode = dfpSessionToClone.getNetworkCode(); this.oAuth2Credential = dfpSessionToClone.getOAuth2Credential(); } @Override public Builder fromFile() throws ConfigurationLoadException { return fromFile(Builder.DEFAULT_CONFIGURATION_FILENAME); } @Override public Builder fromFile(String path) throws ConfigurationLoadException { return from(configHelper.fromFile(path)); } @Override public Builder fromFile(File path) throws ConfigurationLoadException { return from(configHelper.fromFile(path)); } @Override public Builder fromFile(URL path) throws ConfigurationLoadException { return from(configHelper.fromFile(path)); } /** * Reads properties from the provided {@link Configuration} object.<br> * <br> * Known properties: * <ul> * <li>api.dfp.applicationName</li> * <li>api.dfp.networkCode</li> * <li>api.dfp.endpoint</li> * </ul> * * @param config the configuration * @return Builder populated from the configuration */ @Override public Builder from(Configuration config) { this.applicationName = config.getString("api.dfp.applicationName", null); this.networkCode = config.getString("api.dfp.networkCode", null); this.endpoint = config.getString("api.dfp.endpoint", null); return this; } /** * Includes OAuth2 credential to be used for OAuth2 authentication. */ public Builder withOAuth2Credential(Credential oAuth2Credential) { clearAuthentication(); this.oAuth2Credential = oAuth2Credential; return this; } /** * Includes network code. Required for most service calls. */ public Builder withNetworkCode(String networkCode) { this.networkCode = networkCode; return this; } /** * Includes application name (any string of your choice). Required. */ public Builder withApplicationName(String applicationName) { this.applicationName = applicationName; return this; } /** * Override the endpoint server. Optional and defaults to * https://ads.google.com/. */ public Builder withEndpoint(String endpoint) { this.endpoint = endpoint; return this; } /** * Clears all the authentication credentials from this session. */ private void clearAuthentication() { oAuth2Credential = null; } /** * Builds the {@code DfpSession}. * * @return the built {@code DfpSession} * @throws ValidationException if the {@code DfpSession} did not validate */ @Override public DfpSession build() throws ValidationException { defaultOptionals(); validate(); return new DfpSession(this); } /** * Builds a thread-safe {@link ImmutableDfpSession}. * @return the built {@code ImmutableDfpSession} * @throws ValidationException if the attributes of this builder fail validation */ public ImmutableDfpSession buildImmutable() throws ValidationException { defaultOptionals(); validate(); return new ImmutableDfpSession(this); } /** * Fills in defaults if {@code null}. */ private void defaultOptionals() { if (this.endpoint == null) { this.endpoint = DEFAULT_ENDPOINT; } } /** * Validates the properties for the DFP session. */ private void validate() throws ValidationException { // Check for at least one authentication mechanism. if (this.oAuth2Credential == null) { throw new ValidationException( "OAuth2 authentication must be used.", ""); } // Check that application name is not empty or the default. if (Strings.nullToEmpty(applicationName).trim().isEmpty() || applicationName.contains(DEFAULT_APPLICATION_NAME)) { throw new ValidationException(String.format( "Application name must be set and not be the default [%s]", DEFAULT_APPLICATION_NAME), "applicationName"); } // Make sure they specify a valid endpoint. try { new URL(this.endpoint); } catch (MalformedURLException e) { throw new ValidationException(String.format("Endpoint [%s] not recognized as a valid URL.", this.endpoint), "endpoint", e); } } } }