Java tutorial
package com.smartsheet.api.internal; /* * #[license] * Smartsheet SDK for Java * %% * Copyright (C) 2014 Smartsheet * %% * 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. * %[license] */ import com.smartsheet.api.*; import com.smartsheet.api.internal.http.DefaultHttpClient; import com.smartsheet.api.internal.http.HttpClient; import com.smartsheet.api.internal.json.JacksonJsonSerializer; import com.smartsheet.api.internal.json.JsonSerializer; import com.smartsheet.api.internal.util.Util; import org.apache.http.impl.client.HttpClients; import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; /** * This is the implementation of Smartsheet interface. * * Thread Safety: This class is thread safe because all its mutable fields are safe-guarded using AtomicReference to * ensure atomic modifications, and also the underlying HttpClient and JsonSerializer interfaces are thread safe. */ public class SmartsheetImpl implements Smartsheet { /** * Represents the base URI of the Smartsheet REST API. * * It will be initialized in constructor and will not change afterwards. */ private URI baseURI; /** * Represents the AtomicReference for access token. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and can be set via corresponding setter, therefore effectively the access token can be updated in the * SmartsheetImpl in thread safe manner. */ private final AtomicReference<String> accessToken; /** * Represents the HttpClient. * * It will be initialized in constructor and will not change afterwards. */ private final HttpClient httpClient; /** * Represents the JsonSerializer. * * It will be initialized in constructor and will not change afterwards. */ private JsonSerializer jsonSerializer; /** * Represents the AtomicReference for assumed user email. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and can be set via corresponding setter, therefore effectively the assumed user can be updated in the * SmartsheetImpl in thread safe manner. */ private final AtomicReference<String> assumedUser; /** * Represents the AtomicReference for change agent * * It will be initialized in constructor and will not change afterwards. * */ private final AtomicReference<String> changeAgent; /** * Represents the AtomicReference for the user agent */ private final AtomicReference<String> userAgent; /** * Represents the AtomicReference to HomeResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<HomeResources> home; /** * Represents the AtomicReference to WorkspaceResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<WorkspaceResources> workspaces; /** * Represents the AtomicReference to FolderResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<FolderResources> folders; /** * Represents the AtomicReference to TemplateResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<TemplateResources> templates; /** * Represents the AtomicReference to SheetResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<SheetResources> sheets; /** * Represents the AtomicReference to SightResources * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<SightResources> sights; /** * Represents the AtomicReference to UserResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<UserResources> users; /** * Represents the AtomicReference to {@link GroupResources}. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<GroupResources> groups; /** * Represents the AtomicReference to SearchResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<SearchResources> search; /** * Represents the AtomicReference to ReportResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private AtomicReference<ReportResources> reports; /** * Represents the AtomicReference for ServerInfoResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<ServerInfoResources> serverInfo; /** * Represents the AtomicReference for FavoriteResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<FavoriteResources> favorites; /** * Represents the AtomicReference for TokenResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<TokenResources> tokens; /** * Represents the AtomicReference for ContactResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<ContactResources> contacts; /** * Represents the AtomicReference for ImageUrlResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<ImageUrlResources> imageUrls; /** * Represents the AtomicReference for WebhookResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<WebhookResources> webhooks; /** * Represents the AtomicReference for PassthroughResources. * * It will be initialized in constructor and will not change afterwards. The underlying value will be initially set * as null, and will be initialized to non-null at the first time it is accessed via corresponding getter, therefore * effectively the underlying value is lazily created in a thread safe manner. */ private final AtomicReference<PassthroughResources> passthrough; /** * Create an instance with given server URI, HttpClient (optional) and JsonSerializer (optional) * * Exceptions: - IllegalArgumentException : if serverURI/version/accessToken is null/empty * * @param baseURI the server uri * @param accessToken the access token */ public SmartsheetImpl(String baseURI, String accessToken) { this(baseURI, accessToken, null, null); } /** * Create an instance with given server URI, HttpClient (optional) and JsonSerializer (optional) * * Exceptions: - IllegalArgumentException : if serverURI/version/accessToken is null/empty * * @param baseURI the server uri * @param accessToken the access token * @param httpClient the http client (optional) * @param jsonSerializer the json serializer (optional) */ public SmartsheetImpl(String baseURI, String accessToken, HttpClient httpClient, JsonSerializer jsonSerializer) { Util.throwIfNull(baseURI); Util.throwIfEmpty(baseURI); this.baseURI = URI.create(baseURI); this.accessToken = new AtomicReference<String>(accessToken); this.jsonSerializer = ((jsonSerializer == null) ? new JacksonJsonSerializer() : jsonSerializer); this.httpClient = ((httpClient == null) ? new DefaultHttpClient(HttpClients.createDefault(), this.jsonSerializer) : httpClient); this.assumedUser = new AtomicReference<String>(null); this.changeAgent = new AtomicReference<String>(null); this.userAgent = new AtomicReference<String>(generateUserAgent(null)); // Initialize resources this.home = new AtomicReference<HomeResources>(); this.workspaces = new AtomicReference<WorkspaceResources>(); this.folders = new AtomicReference<FolderResources>(); this.templates = new AtomicReference<TemplateResources>(); this.sheets = new AtomicReference<SheetResources>(); this.sights = new AtomicReference<SightResources>(); this.favorites = new AtomicReference<FavoriteResources>(); this.users = new AtomicReference<UserResources>(); this.groups = new AtomicReference<GroupResources>(); this.search = new AtomicReference<SearchResources>(); this.reports = new AtomicReference<ReportResources>(); this.serverInfo = new AtomicReference<ServerInfoResources>(); this.tokens = new AtomicReference<TokenResources>(); this.contacts = new AtomicReference<ContactResources>(); this.imageUrls = new AtomicReference<ImageUrlResources>(); this.webhooks = new AtomicReference<WebhookResources>(); this.passthrough = new AtomicReference<PassthroughResources>(); } /** * Finalize the object, this method is overridden to close the HttpClient. * * @throws IOException Signals that an I/O exception has occurred. */ protected void finalize() throws IOException { this.httpClient.close(); } /** * Getter of corresponding field. * * Returns: corresponding field. * * @return the base uri */ URI getBaseURI() { return baseURI; } /** * Return the access token * * @return the access token */ String getAccessToken() { return accessToken.get(); } /** * Set the access token to use. * * Parameters: - accessToken : the access token * * Returns: None * * * @param accessToken the new access token */ public void setAccessToken(String accessToken) { this.accessToken.set(accessToken); } /** * Getter of corresponding field. * * @return corresponding field */ JsonSerializer getJsonSerializer() { return jsonSerializer; } /** * Getter of corresponding field. * * @return corresponding field. */ HttpClient getHttpClient() { return httpClient; } /** * Return the assumed user. * * @return the assumed user */ String getAssumedUser() { return assumedUser.get(); } /** * Set the email of the user to assume. Null/empty string indicates no user is assumed. * * @param assumedUser the email of the user to assume */ public void setAssumedUser(String assumedUser) { this.assumedUser.set(assumedUser); } /** * Return the change agent identifier. * * @return the access token */ String getChangeAgent() { return changeAgent.get(); } /** * Sets the change agent identifier * * @param changeAgent */ public void setChangeAgent(String changeAgent) { this.changeAgent.set(changeAgent); } /** * Return the user agent string * * @return the user agent string */ public String getUserAgent() { return userAgent.get(); } /** * Sets the user agent string * * @param userAgent the user agent string */ public void setUserAgent(String userAgent) { this.userAgent.set(generateUserAgent(userAgent)); } /** * Sets the max retry time if the HttpClient is an instance of DefaultHttpClient * * @param maxRetryTimeMillis max retry time */ public void setMaxRetryTimeMillis(long maxRetryTimeMillis) { if (this.httpClient instanceof DefaultHttpClient) { ((DefaultHttpClient) this.httpClient).setMaxRetryTimeMillis(maxRetryTimeMillis); } else throw new UnsupportedOperationException("Invalid operation for class " + this.httpClient.getClass()); } /** set what request/response fields to log in trace-logging */ public void setTraces(Trace... traces) { if (this.httpClient instanceof DefaultHttpClient) { ((DefaultHttpClient) this.httpClient).setTraces(traces); } else throw new UnsupportedOperationException("Invalid operation for class " + this.httpClient.getClass()); } /** set whether or not to generate "pretty formatted" JSON in trace-logging */ public void setTracePrettyPrint(boolean pretty) { if (this.httpClient instanceof DefaultHttpClient) { ((DefaultHttpClient) this.httpClient).setTracePrettyPrint(pretty); } else throw new UnsupportedOperationException("Invalid operation for class " + this.httpClient.getClass()); } /** * Returns the HomeResources instance that provides access to Home resources. * * @return the home resources */ public HomeResources homeResources() { if (home.get() == null) { home.compareAndSet(null, new HomeResourcesImpl(this)); } return home.get(); } /** * Returns the WorkspaceResources instance that provides access to Workspace resources. * * @return the workspace resources */ public WorkspaceResources workspaceResources() { if (workspaces.get() == null) { workspaces.compareAndSet(null, new WorkspaceResourcesImpl(this)); } return workspaces.get(); } /** * Returns the FolderResources instance that provides access to Folder resources. * * @return the folder resources */ public FolderResources folderResources() { if (folders.get() == null) { folders.compareAndSet(null, new FolderResourcesImpl(this)); } return folders.get(); } /** * Returns the TemplateResources instance that provides access to Template resources. * * @return the template resources */ public TemplateResources templateResources() { if (templates.get() == null) { templates.compareAndSet(null, new TemplateResourcesImpl(this)); } return templates.get(); } /** * Returns the SheetResources instance that provides access to Sheet resources. * * @return the sheet resources */ public SheetResources sheetResources() { if (sheets.get() == null) { sheets.compareAndSet(null, new SheetResourcesImpl(this)); } return sheets.get(); } /** * Returns the SightResources instance that provides access to Sight resources. * * @return the sight resources */ public SightResources sightResources() { if (sights.get() == null) { sights.compareAndSet(null, new SightResourcesImpl(this)); } return sights.get(); } /** * Returns the FavoriteResources instance that provides access to Favorite resources. * * @return the favorite resources */ public FavoriteResources favoriteResources() { if (favorites.get() == null) { favorites.compareAndSet(null, new FavoriteResourcesImpl(this)); } return favorites.get(); } /** * Returns the {@link UserResources} instance that provides access to User resources. * * @return the user resources */ public UserResources userResources() { if (users.get() == null) { users.compareAndSet(null, new UserResourcesImpl(this)); } return users.get(); } /** * Returns the {@link GroupResources} instance that provides access to User resources. * * @return the user resources */ public GroupResources groupResources() { if (groups.get() == null) { groups.compareAndSet(null, new GroupResourcesImpl(this)); } return groups.get(); } /** * Returns the {@link SearchResources} instance that provides access to searching resources. * * @return the search resources */ public SearchResources searchResources() { if (search.get() == null) { search.compareAndSet(null, new SearchResourcesImpl(this)); } return search.get(); } /** * Returns the {@link ReportResources} instance that provides access to Report resources. * * @return the report resources */ public ReportResources reportResources() { if (reports.get() == null) { reports.compareAndSet(null, new ReportResourcesImpl(this)); } return reports.get(); } /** * Returns the {@link ServerInfoResources} instance that provides access to ServerInfo resources. * * @return the ServerInfo resources */ public ServerInfoResources serverInfoResources() { if (serverInfo.get() == null) { serverInfo.compareAndSet(null, new ServerInfoResourcesImpl(this)); } return serverInfo.get(); } /** * Returns the TokenResources instance that provides access to token resources. * * @return the token resources */ public TokenResources tokenResources() { if (tokens.get() == null) { tokens.compareAndSet(null, new TokenResourcesImpl(this)); } return tokens.get(); } /** * Returns the ContactResources instance that provides access to contact resources. * * @return the contact resources */ public ContactResources contactResources() { if (contacts.get() == null) { contacts.compareAndSet(null, new ContactResourcesImpl(this)); } return contacts.get(); } /** * Returns the ImageUrlResources instance that provides access to image url resources. * * @return the image url resources */ public ImageUrlResources imageUrlResources() { if (imageUrls.get() == null) { imageUrls.compareAndSet(null, new ImageUrlResourcesImpl(this)); } return imageUrls.get(); } /** * Returns the WebhookResources instance that provides access to webhook resources. * * @return the webhook resources */ public WebhookResources webhookResources() { if (webhooks.get() == null) { webhooks.compareAndSet(null, new WebhookResourcesImpl(this)); } return webhooks.get(); } /** * Returns the PassthroughResources instance that provides access to passthrough resources. * * @return the passthrough resources */ public PassthroughResources passthroughResources() { if (passthrough.get() == null) { passthrough.compareAndSet(null, new PassthroughResourcesImpl(this)); } return passthrough.get(); } /** * Compose a User-Agent string that represents this version of the SDK (along with platform info) * * @return a User-Agent string */ private String generateUserAgent(String userAgent) { String title = null; String thisVersion = null; if (userAgent == null) { StackTraceElement[] callers = Thread.currentThread().getStackTrace(); String module = null; String callerClass = null; int stackIdx; for (stackIdx = callers.length - 1; stackIdx >= 0; stackIdx--) { callerClass = callers[stackIdx].getClassName(); try { Class<?> clazz = Class.forName(callerClass); ClassLoader classLoader = clazz.getClassLoader(); // skip JRE classes if (classLoader == null) { continue; } String classFilePath = callerClass.replace(".", "/") + ".class"; URL classUrl = classLoader.getResource(classFilePath); if (classUrl != null) { String classUrlPath = classUrl.getPath(); int jarSeparator = classUrlPath.indexOf('!'); if (jarSeparator > 0) { module = classUrlPath.substring(0, jarSeparator); // extract the last path element (the jar name only) module = module.substring(module.lastIndexOf('/') + 1); break; } } } catch (Exception ex) { } } userAgent = module + "!" + callerClass; } try { final Properties properties = new Properties(); properties.load(this.getClass().getClassLoader().getResourceAsStream("sdk.properties")); thisVersion = properties.getProperty("sdk.version"); title = properties.getProperty("sdk.name"); } catch (IOException e) { } return title + "/" + thisVersion + "/" + userAgent + "/" + System.getProperty("os.name") + " " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vendor") + " " + System.getProperty("java.version"); } }