View Javadoc

1   /*
2    * Copyright (C) 2012-2013 Atlassian
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  package com.atlassian.jira.rest.client.internal.json;
18  
19  import com.atlassian.jira.rest.client.api.domain.CimFieldInfo;
20  import com.atlassian.jira.rest.client.api.domain.FieldSchema;
21  import com.atlassian.jira.rest.client.api.domain.StandardOperation;
22  import com.google.common.collect.ImmutableSet;
23  import com.google.common.collect.Lists;
24  import com.google.common.collect.Maps;
25  import com.google.common.collect.Sets;
26  import org.codehaus.jettison.json.JSONArray;
27  import org.codehaus.jettison.json.JSONException;
28  import org.codehaus.jettison.json.JSONObject;
29  
30  import javax.annotation.Nullable;
31  import java.net.URI;
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Set;
38  
39  /**
40   * JSON parser that produces Map of String => CimFieldInfo
41   *
42   * @since v1.0
43   */
44  public class CimFieldsInfoMapJsonParser implements JsonObjectParser<Map<String, CimFieldInfo>> {
45  
46  	private final FieldSchemaJsonParser fieldSchemaJsonParser = new FieldSchemaJsonParser();
47  
48  	protected final Map<String, JsonObjectParser> registeredAllowedValueParsers = new HashMap<String, JsonObjectParser>() {{
49  		put("project", new BasicProjectJsonParser());
50  		put("version", new VersionJsonParser());
51  		put("issuetype", new BasicIssueTypeJsonParser());
52  		put("priority", new BasicPriorityJsonParser());
53  		put("customFieldOption", new CustomFieldOptionJsonParser());
54  		put("component", new BasicComponentJsonParser());
55  		put("resolution", new BasicResolutionJsonParser());
56  		put("securitylevel", new SecurityLevelJsonParser());
57  	}};
58  
59  	@Override
60  	public Map<String, CimFieldInfo> parse(JSONObject json) throws JSONException {
61  		final Map<String, CimFieldInfo> res = Maps.newHashMapWithExpectedSize(json.length());
62  		final Iterator keysIterator = json.keys();
63  		while (keysIterator.hasNext()) {
64  			final String id = (String) keysIterator.next();
65  			res.put(id, parseIssueFieldInfo(json.getJSONObject(id), id));
66  		}
67  		return res;
68  	}
69  
70  	private CimFieldInfo parseIssueFieldInfo(JSONObject json, String id) throws JSONException {
71  		final boolean required = json.getBoolean("required");
72  		final String name = JsonParseUtil.getOptionalString(json, "name");
73  		final FieldSchema schema = fieldSchemaJsonParser.parse(json.getJSONObject("schema"));
74  		final Set<StandardOperation> operations = parseOperations(json.getJSONArray("operations"));
75  		final Iterable<Object> allowedValues = parseAllowedValues(json.optJSONArray("allowedValues"), schema);
76  		final URI autoCompleteUri = JsonParseUtil.parseOptionalURI(json, "autoCompleteUrl");
77  
78  		return new CimFieldInfo(id, required, name, schema, operations, allowedValues, autoCompleteUri);
79  	}
80  
81  	private Iterable<Object> parseAllowedValues(@Nullable JSONArray allowedValues, FieldSchema fieldSchema) throws JSONException {
82  		if (allowedValues == null || allowedValues.equals(JSONObject.NULL)) {
83  			return null;
84  		}
85  
86  		if (allowedValues.length() == 0) {
87  			return Collections.emptyList();
88  		}
89  
90  		final JsonObjectParser<Object> allowedValuesJsonParser = getParserFor(fieldSchema);
91  		if (allowedValuesJsonParser != null) {
92  			JSONArray valuesToParse;
93  			// fixes for JRADEV-12999
94  			final boolean isProjectCF = "project".equals(fieldSchema.getType())
95  					&& "com.atlassian.jira.plugin.system.customfieldtypes:project".equals(fieldSchema.getCustom());
96  			final boolean isVersionCF = "version".equals(fieldSchema.getType())
97  					&& "com.atlassian.jira.plugin.system.customfieldtypes:version".equals(fieldSchema.getCustom());
98  			final boolean isMultiVersionCF = "array".equals(fieldSchema.getType())
99  					&& "version".equals(fieldSchema.getItems())
100 					&& "com.atlassian.jira.plugin.system.customfieldtypes:multiversion".equals(fieldSchema.getCustom());
101 
102 			if ((isProjectCF || isVersionCF || isMultiVersionCF) && allowedValues.get(0) instanceof JSONArray) {
103 				valuesToParse = allowedValues.getJSONArray(0);
104 			} else {
105 				valuesToParse = allowedValues;
106 			}
107 			return GenericJsonArrayParser.create(allowedValuesJsonParser).parse(valuesToParse);
108 		} else {
109 			// fallback - just return collection of JSONObjects
110 			final int itemsLength = allowedValues.length();
111 			final List<Object> res = Lists.newArrayListWithExpectedSize(itemsLength);
112 			for (int i = 0; i < itemsLength; i++) {
113 				res.add(allowedValues.get(i));
114 			}
115 			return res;
116 		}
117 	}
118 
119 	private Set<StandardOperation> parseOperations(JSONArray operations) throws JSONException {
120 		final int operationsCount = operations.length();
121 		final Set<StandardOperation> res = Sets.newHashSetWithExpectedSize(operationsCount);
122 		for (int i = 0; i < operationsCount; i++) {
123 			String opName = operations.getString(i);
124 			StandardOperation op = StandardOperation.valueOf(opName.toUpperCase());
125 			res.add(op);
126 		}
127 		return res;
128 	}
129 
130 	@Nullable
131 	private JsonObjectParser<Object> getParserFor(FieldSchema fieldSchema) throws JSONException {
132 		final Set<String> customFieldsTypesWithFieldOption = ImmutableSet.of(
133 				"com.atlassian.jira.plugin.system.customfieldtypes:multicheckboxes",
134 				"com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons",
135 				"com.atlassian.jira.plugin.system.customfieldtypes:select",
136 				"com.atlassian.jira.plugin.system.customfieldtypes:cascadingselect",
137 				"com.atlassian.jira.plugin.system.customfieldtypes:multiselect"
138 		);
139 		String type = "array".equals(fieldSchema.getType()) ? fieldSchema.getItems() : fieldSchema.getType();
140 		final String custom = fieldSchema.getCustom();
141 		if (custom != null && customFieldsTypesWithFieldOption.contains(custom)) {
142 			type = "customFieldOption";
143 		}
144 		@SuppressWarnings("unchecked")
145 		final JsonObjectParser<Object> jsonParser = registeredAllowedValueParsers.get(type);
146 		if (jsonParser == null) {
147 			return null;
148 		} else {
149 			return jsonParser;
150 		}
151 	}
152 }