OLD | NEW |
| (Empty) |
1 /* | |
2 Copyright 2011 Google Inc | |
3 | |
4 Licensed under the Apache License, Version 2.0 (the "License"); | |
5 you may not use this file except in compliance with the License. | |
6 You may obtain a copy of the License at | |
7 | |
8 http://www.apache.org/licenses/LICENSE-2.0 | |
9 | |
10 Unless required by applicable law or agreed to in writing, software | |
11 distributed under the License is distributed on an "AS IS" BASIS, | |
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 See the License for the specific language governing permissions and | |
14 limitations under the License. | |
15 */ | |
16 | |
17 using System.Collections.Generic; | |
18 using Google.Apis.Discovery; | |
19 using Google.Apis.Discovery.Schema; | |
20 using Google.Apis.Testing; | |
21 using Google.Apis.Util; | |
22 using Newtonsoft.Json.Schema; | |
23 | |
24 namespace Google.Apis.Tools.CodeGen.Generator | |
25 { | |
26 /// <summary> | |
27 /// Generator for the SchemaImplementationDetails class.· | |
28 /// Scans the resources and other fields of a discovered services to provide
additional information | |
29 /// for the schema decorators, which cannot be found within the json of a sc
hema. | |
30 /// Amongst others used by the ErrorResponseDecorator to find out which sche
mas are referred by methods. | |
31 /// </summary> | |
32 public class ImplementationDetailsGenerator | |
33 { | |
34 /// <summary> | |
35 /// Suffix which will be attached to all nested classes for properties w
hich do not refer to a strongly | |
36 /// named type. | |
37 /// </summary> | |
38 public const string PropertyClassSuffix = "Data"; | |
39 | |
40 /// <summary> | |
41 /// Generates the implementation details for a whole service. | |
42 /// </summary> | |
43 public IDictionary<JsonSchema, SchemaImplementationDetails> GenerateDeta
ils(IService service) | |
44 { | |
45 service.ThrowIfNull("service"); | |
46 | |
47 Dictionary<JsonSchema, SchemaImplementationDetails> dictionary = | |
48 new Dictionary<JsonSchema, SchemaImplementationDetails>(); | |
49 | |
50 // Traverse through all schemas and check if they require implementa
tion details. | |
51 foreach (ISchema schema in service.Schemas.Values) | |
52 { | |
53 if (schema.SchemaDetails != null) | |
54 { | |
55 AddDetails(dictionary, schema.SchemaDetails); | |
56 } | |
57 } | |
58 | |
59 // Create additional details for all schemas where they are necessar
y. | |
60 AddIsMethodResult(dictionary, service, service.Resources.Values); | |
61 | |
62 return dictionary; | |
63 } | |
64 | |
65 /// <summary> | |
66 /// Adds implementation details for the specified schema and all its sub
schemas if they are required/useful. | |
67 /// </summary> | |
68 [VisibleForTestOnly] | |
69 internal static void AddDetails(IDictionary<JsonSchema, SchemaImplementa
tionDetails> dictionary, | |
70 JsonSchema schema) | |
71 { | |
72 // Add details for this schema | |
73 SchemaImplementationDetails details = GetOrCreateDetails(dictionary,
schema); | |
74 if (details.TraversedByGenerator) | |
75 { | |
76 // This scheme has already been fully generated | |
77 return; | |
78 } | |
79 details.TraversedByGenerator = true; | |
80 | |
81 // Check for properties: | |
82 if (schema.Properties != null) | |
83 { | |
84 foreach (KeyValuePair<string, JsonSchema> property in schema.Pro
perties) | |
85 { | |
86 ProposeNameIfNecessary(dictionary, property.Key + PropertyCl
assSuffix, property.Value); | |
87 AddDetails(dictionary, property.Value); | |
88 } | |
89 } | |
90 | |
91 // Generate a template name for subclasses. | |
92 string proposedName = schema.Id.IsNotNullOrEmpty() ? schema.Id : det
ails.ProposedName; | |
93 | |
94 // Check for items: | |
95 if (schema.Items != null) | |
96 { | |
97 // Iterate through items and check if they require a name. | |
98 foreach (JsonSchema item in schema.Items) | |
99 { | |
100 // Set the name if necessary and possible. | |
101 if (!string.IsNullOrEmpty(proposedName)) | |
102 { | |
103 ProposeNameIfNecessary(dictionary, proposedName, item); | |
104 } | |
105 AddDetails(dictionary, item); | |
106 } | |
107 } | |
108 | |
109 // Check additional properties: | |
110 if (schema.AdditionalProperties != null) | |
111 { | |
112 ProposeNameIfNecessary(dictionary, proposedName + "Properties",
schema.AdditionalProperties); | |
113 AddDetails(dictionary, schema.AdditionalProperties); | |
114 } | |
115 } | |
116 | |
117 /// <summary> | |
118 /// Proposes a name for a schema if it has none yet. | |
119 /// </summary> | |
120 [VisibleForTestOnly] | |
121 internal static void ProposeNameIfNecessary(IDictionary<JsonSchema, Sche
maImplementationDetails> dictionary, | |
122 string name, | |
123 JsonSchema schema) | |
124 { | |
125 schema.ThrowIfNull("schema"); | |
126 name.ThrowIfNull("name"); | |
127 dictionary.ThrowIfNull("name"); | |
128 | |
129 if (schema.Id.IsNotNullOrEmpty()) | |
130 { | |
131 // Already has a name -> return. | |
132 return; | |
133 } | |
134 | |
135 SchemaImplementationDetails details = GetOrCreateDetails(dictionary,
schema); | |
136 if (string.IsNullOrEmpty(details.ProposedName)) | |
137 { | |
138 details.ProposedName = name; | |
139 } | |
140 } | |
141 | |
142 [VisibleForTestOnly] | |
143 internal static SchemaImplementationDetails GetOrCreateDetails( | |
144 IDictionary<JsonSchema, SchemaImplementationDetails> details, JsonSc
hema schema) | |
145 { | |
146 details.ThrowIfNull("details"); | |
147 schema.ThrowIfNull("schema"); | |
148 | |
149 // If no implementation details have been added yet, create a new en
try); | |
150 if (!details.ContainsKey(schema)) | |
151 { | |
152 details.Add(schema, new SchemaImplementationDetails()); | |
153 } | |
154 return details[schema]; | |
155 } | |
156 | |
157 | |
158 [VisibleForTestOnly] | |
159 internal static void AddIsMethodResult(IDictionary<JsonSchema, SchemaImp
lementationDetails> details, | |
160 IService service, | |
161 IEnumerable<IResource> resources) | |
162 { | |
163 details.ThrowIfNull("details"); | |
164 service.ThrowIfNull("service"); | |
165 resources.ThrowIfNull("method"); | |
166 | |
167 foreach (IResource resource in resources) | |
168 { | |
169 // Check methods | |
170 foreach (IMethod method in resource.Methods.Values) | |
171 { | |
172 AddIsMethodResult(details, service, method); | |
173 } | |
174 | |
175 // Check subresources (if applicable) | |
176 if (resource.Resources != null) | |
177 { | |
178 AddIsMethodResult(details, service, resource.Resources.Value
s); | |
179 } | |
180 } | |
181 } | |
182 | |
183 [VisibleForTestOnly] | |
184 internal static void AddIsMethodResult(IDictionary<JsonSchema, SchemaImp
lementationDetails> details, | |
185 IService service, | |
186 IMethod method) | |
187 { | |
188 details.ThrowIfNull("details"); | |
189 service.ThrowIfNull("service"); | |
190 method.ThrowIfNull("method"); | |
191 | |
192 string id = method.ResponseType; | |
193 | |
194 if (string.IsNullOrEmpty(id)) | |
195 { | |
196 // Return if this method has no response type | |
197 return;· | |
198 } | |
199 | |
200 // Check if this name is a valid schema | |
201 if (!service.Schemas.ContainsKey(id)) | |
202 { | |
203 return; | |
204 } | |
205 | |
206 ISchema schema = service.Schemas[id]; | |
207 | |
208 // If no implementation details have been added yet, create a new en
try | |
209 SchemaImplementationDetails implementationDetails = GetOrCreateDetai
ls(details, schema.SchemaDetails); | |
210 | |
211 // Change the value | |
212 implementationDetails.IsMethodResult = true; | |
213 } | |
214 } | |
215 } | |
OLD | NEW |