| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. See License.txt in the project root for license information. |
| | 3 | |
|
| | 4 | | namespace Microsoft.Azure.Batch |
| | 5 | | { |
| | 6 | | using System; |
| | 7 | | using System.Collections.Generic; |
| | 8 | | using System.Globalization; |
| | 9 | | using Protocol.Models; |
| | 10 | |
|
| | 11 | | /// <summary> |
| | 12 | | /// Controls the amount of detail requested from the Azure Batch service when listing or |
| | 13 | | /// retrieving resources, using OData query clauses. |
| | 14 | | /// </summary> |
| | 15 | | /// <remarks> |
| | 16 | | /// <para>Azure Batch supports OData queries, which allow the client to gain finer control over query |
| | 17 | | /// performance by controlling which resources are returned in List operations (<see cref="FilterClause"/>), |
| | 18 | | /// and which properties of each resource are returned in List, Get or Refresh operations |
| | 19 | | /// (<see cref="SelectClause"/> and <see cref="ExpandClause"/>).</para> |
| | 20 | | /// <para>By default, if you do not pass a <see cref="DetailLevel"/> to a List, Get or Refresh operation, |
| | 21 | | /// the Batch client specifies no filter (all records are returned), no select clause (all simple properties are |
| | 22 | | /// returned) and no expand clause (associated entities are not returned). Consequently, by default, associated ent |
| | 23 | | /// properties are null, rather than being populated like other properties. Refer to individual class |
| | 24 | | /// documentation to find out which properties are considered associated entities and need to be expanded |
| | 25 | | /// to be populated.</para> |
| | 26 | | /// <para>Because the OData queries are passed directly to the REST API, clause strings must use the JSON attribute |
| | 27 | | /// names from the REST API, which are not always the same as .NET property names. For example, the |
| | 28 | | /// .NET <see cref="CloudPool.VirtualMachineSize">CloudPool.VirtualMachineSize</see> property corresponds to |
| | 29 | | /// the vmSize attribute in the REST API; therefore, to filter a pool list operations by VM size, you would |
| | 30 | | /// need to write vmSize rather than VirtualMachineSize in your filter string. Refer to the REST API |
| | 31 | | /// documentation to find out the JSON attribute name corresponding to a .NET property.</para> |
| | 32 | | /// <para>For additional information about using OData to efficiently query the Azure Batch service, see |
| | 33 | | /// <a href="https://azure.microsoft.com/en-us/documentation/articles/batch-efficient-list-queries/">Efficient List |
| | 34 | | /// </remarks> |
| | 35 | | /// <example> |
| | 36 | | /// This sample shows how to specify an ODataDetailLevel that lists only active <see cref="CloudPool">CloudPools</se |
| | 37 | | /// and retrieves only the <see cref="CloudPool.Id"/>, <see cref="CloudPool.DisplayName"/> and <see cref="CloudPool. |
| | 38 | | /// for each pool (for example, for display in a reporting user interface). |
| | 39 | | /// <code> |
| | 40 | | /// var detailLevel = new ODATADetailLevel( |
| | 41 | | /// filterClause: "state eq 'active'", |
| | 42 | | /// selectClause: "id,displayName,stats", |
| | 43 | | /// expandClause: "stats" |
| | 44 | | /// ); |
| | 45 | | /// |
| | 46 | | /// var pools = batchClient.PoolOperations.ListPools(detailLevel); |
| | 47 | | /// </code> |
| | 48 | | /// </example> |
| | 49 | | public class ODATADetailLevel : DetailLevel |
| | 50 | | { |
| | 51 | | /// <summary> |
| | 52 | | /// Gets or sets the OData filter clause. Used to restrict a list operation to items that match specified criter |
| | 53 | | /// </summary> |
| | 54 | | /// <remarks> |
| | 55 | | /// <para>This is an optional OData $filter expression string |
| | 56 | | /// <a href="http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-e |
| | 57 | | /// For example, you can restrict a <see cref="PoolOperations.ListPools(DetailLevel, IEnumerable{BatchClientBeha |
| | 58 | | /// only active pools with the expression <c>state eq 'active'</c>.</para> |
| | 59 | | /// <para>Filters must be specified using REST API attribute names, not .NET property names.</para> |
| | 60 | | /// <para>The default is no filter expression, which means all resources are returned.</para> |
| | 61 | | /// </remarks> |
| 28 | 62 | | public string FilterClause { get; set; } |
| | 63 | |
|
| | 64 | | /// <summary> |
| | 65 | | /// Gets or sets the OData select clause. Used to retrieve only specific properties instead of all object proper |
| | 66 | | /// </summary> |
| | 67 | | /// <remarks> |
| | 68 | | /// <para>This is an optional OData $select expression string |
| | 69 | | /// <a href="http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-e |
| | 70 | | /// If you provide a SelectClause, then <b>only</b> the properties listed in that clause are populated; other pr |
| | 71 | | /// have their default values (typically null). For example, if you perform a <see cref="PoolOperations.ListPoo |
| | 72 | | /// operation with a SelectClause of <c>id,displayName</c>, then each <see cref="CloudPool"/> will have its |
| | 73 | | /// <see cref="CloudPool.Id"/> and <see cref="CloudPool.DisplayName"/> properties |
| | 74 | | /// populated, but other properties such as <see cref="CloudPool.State"/> will not be retrieved and therefore |
| | 75 | | /// will have their default values (typically null).</para> |
| | 76 | | /// <para>If, when an entity was retrieved (via a List, Get or Refresh), you specifed a SelectClause which did n |
| | 77 | | /// the property or properties that uniquely identify the object |
| | 78 | | /// (usually the Id property, but for <see cref="Certificate"/> the Thumbprint and ThumbprintAlgorithm propertie |
| | 79 | | /// then any methods that access the Batch service to retrieve data or perform operations will fail. |
| | 80 | | /// This includes most methods on the object, including <see cref="IRefreshable.Refresh"/> and <see cref="IRefre |
| | 81 | | /// You can still access properties (though only properties included in the SelectClause will be populated).</pa |
| | 82 | | /// <para>Selections must be specified using REST API attribute names, not .NET property names.</para> |
| | 83 | | /// <para>The default is no select expression, which means all properties are returned.</para> |
| | 84 | | /// </remarks> |
| 28 | 85 | | public string SelectClause { get; set; } |
| | 86 | |
|
| | 87 | | /// <summary> |
| | 88 | | /// Gets or sets the OData expand clause. Used to retrieve associated entities of the main entity being retrieve |
| | 89 | | /// </summary> |
| | 90 | | /// <remarks> |
| | 91 | | /// <para>This is an optional OData $expand expression string |
| | 92 | | /// <a href="http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-e |
| | 93 | | /// Properties containing associated entities will be null unless included in an ExpandClause. |
| | 94 | | /// Specifically, if you perform a List, Get or Refresh and do not specify an ExpandClause, then all associated |
| | 95 | | /// entity properties will be null. For example, if you perform a <see cref="PoolOperations.ListPools(DetailLev |
| | 96 | | /// operation without an ExpandClause then the <see cref="CloudPool.Statistics"/> property will be null. To pop |
| | 97 | | /// the Statistics property you must supply an ExpandClause of <c>stats</c>. Refer to individual class |
| | 98 | | /// documentation to find out which properties are considered associated entities.</para> |
| | 99 | | /// <para>If you specify both an ExpandClause and a <see cref="SelectClause"/>, then properties listed in the |
| | 100 | | /// ExpandClause must be repeated in the SelectClause (because only properties listed in the SelectClause are |
| | 101 | | /// included in the service response). (This requirement does not arise if you do not specify a SelectClause, b |
| | 102 | | /// means 'include all properties in the response.')</para> |
| | 103 | | /// <para>Expansions must be specified using REST API attribute names, not .NET property names.</para> |
| | 104 | | /// <para>The default is no expand expression, which means no associated objects are returned (and the |
| | 105 | | /// corresponding properties are null).</para> |
| | 106 | | /// </remarks> |
| 24 | 107 | | public string ExpandClause { get; set; } |
| | 108 | |
|
| | 109 | | /// <summary> |
| | 110 | | /// Initializes a new instance of the <see cref="ODATADetailLevel"/> class with the specified clauses. |
| | 111 | | /// </summary> |
| | 112 | | /// <param name="filterClause">The filter clause.</param> |
| | 113 | | /// <param name="selectClause">The select clause.</param> |
| | 114 | | /// <param name="expandClause">The expand clause.</param> |
| 4 | 115 | | public ODATADetailLevel(string filterClause = null, string selectClause = null, string expandClause = null) |
| | 116 | | { |
| 4 | 117 | | this.FilterClause = filterClause; |
| 4 | 118 | | this.SelectClause = selectClause; |
| 4 | 119 | | this.ExpandClause = expandClause; |
| 4 | 120 | | } |
| | 121 | |
|
| | 122 | | /// <summary> |
| | 123 | | /// Initializes a new instance of the <see cref="ODATADetailLevel"/> class with empty clauses. |
| | 124 | | /// </summary> |
| 3 | 125 | | public ODATADetailLevel() |
| | 126 | | { |
| 3 | 127 | | } |
| | 128 | | } |
| | 129 | |
|
| | 130 | | internal class ODATADetailLevelIntercept : Protocol.RequestInterceptor |
| | 131 | | { |
| | 132 | | private readonly ODATADetailLevel _details; |
| | 133 | |
|
| | 134 | | private ODATADetailLevelIntercept() |
| | 135 | | { |
| | 136 | | } |
| | 137 | |
|
| | 138 | | public ODATADetailLevelIntercept(ODATADetailLevel odataDetaillevel) |
| | 139 | | { |
| | 140 | | // remember the values that need to be set |
| | 141 | | _details = odataDetaillevel; |
| | 142 | |
|
| | 143 | | // this is the code that will set the odata predicates |
| | 144 | | base.ModificationInterceptHandler = SetODATAPredicates; |
| | 145 | | } |
| | 146 | |
|
| | 147 | | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2208:VariableNamesShouldNotMatchFieldName |
| | 148 | | private void SetODATAPredicates(Protocol.IBatchRequest request) |
| | 149 | | { |
| | 150 | | IODataFilter filterOptions = request.Options as IODataFilter; |
| | 151 | | IODataExpand expandOptions = request.Options as IODataExpand; |
| | 152 | | IODataSelect selectOptions = request.Options as IODataSelect; |
| | 153 | |
|
| | 154 | | if (filterOptions != null) |
| | 155 | | { |
| | 156 | | filterOptions.Filter = this._details.FilterClause; |
| | 157 | | } |
| | 158 | | else if (!string.IsNullOrEmpty(this._details.FilterClause)) |
| | 159 | | { |
| | 160 | | //Note: We explicitly set this to be "detailLevel" for clarity for the customer even though at this scop |
| | 161 | | throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, BatchErrorMessages.TypeDoesNotSu |
| | 162 | | } |
| | 163 | |
|
| | 164 | | if (expandOptions != null) |
| | 165 | | { |
| | 166 | | expandOptions.Expand = this._details.ExpandClause; |
| | 167 | | } |
| | 168 | | else if (!string.IsNullOrEmpty(this._details.ExpandClause)) |
| | 169 | | { |
| | 170 | | //Note: We explicitly set this to be "detailLevel" for clarity for the customer even though at this scop |
| | 171 | | throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, BatchErrorMessages.TypeDoesNotSu |
| | 172 | | } |
| | 173 | |
|
| | 174 | | if (selectOptions != null) |
| | 175 | | { |
| | 176 | | selectOptions.Select = this._details.SelectClause; |
| | 177 | | } |
| | 178 | | else if (!string.IsNullOrEmpty(this._details.SelectClause)) |
| | 179 | | { |
| | 180 | | //Note: We explicitly set this to be "detailLevel" for clarity for the customer even though at this scop |
| | 181 | | throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, BatchErrorMessages.TypeDoesNotSu |
| | 182 | | } |
| | 183 | | } |
| | 184 | | } |
| | 185 | | } |