App Engine Java SDK version 1.9.25
[gae.git] / java / src / main / com / google / apphosting / utils / config / IndexYamlReader.java
blobce8c67f78a3299ed3c6c0987831ea040aef9a0b8
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.apphosting.utils.config;
5 import static com.google.apphosting.utils.config.IndexesXml.DIRECTION_VALUE_ASC;
6 import static com.google.apphosting.utils.config.IndexesXml.DIRECTION_VALUE_DESC;
7 import static com.google.apphosting.utils.config.IndexesXml.MODE_VALUE_GEOSPATIAL;
9 import net.sourceforge.yamlbeans.YamlException;
10 import net.sourceforge.yamlbeans.YamlReader;
12 import java.io.Reader;
13 import java.io.StringReader;
14 import java.util.LinkedList;
15 import java.util.List;
17 /**
18 * Class to parse index.yaml into a IndexesXml object.
21 public class IndexYamlReader {
23 public static final String INDEX_DEFINITIONS_TAG =
24 "!!python/object:google.appengine.datastore.datastore_index.IndexDefinitions";
25 public static final String INDEX_TAG =
26 "!!python/object:google.appengine.datastore.datastore_index.Index";
27 public static final String PROPERTY_TAG =
28 "!!python/object:google.appengine.datastore.datastore_index.Property";
30 /**
31 * Wrapper around IndexesXml to make the JavaBeans properties match the YAML
32 * file syntax.
34 public static class IndexYaml {
36 public String application;
37 /**
38 * JavaBean wrapper for Index entries in IndexesXml.
40 public static class Index {
41 public String kind;
42 protected boolean ancestor;
43 public List<Property> properties;
45 public void setAncestor(String ancestor) {
46 this.ancestor = YamlUtils.parseBoolean(ancestor);
49 public String getAncestor() {
50 return "" + ancestor;
54 /**
55 * JavaBean wrapper for IndexesXml properties.
57 public static class Property {
58 private String name = null;
59 private String direction = null;
60 private String mode = null;
62 public void setDirection(String direction) {
63 if (DIRECTION_VALUE_DESC.equals(direction)
64 || DIRECTION_VALUE_ASC.equals(direction)) {
65 this.direction = direction;
66 } else {
67 throw new AppEngineConfigException(
68 "Invalid direction '" + direction + "': expected '" + DIRECTION_VALUE_ASC
69 + "' or '" + DIRECTION_VALUE_DESC + "'.");
73 public String getName() {
74 return name;
77 public void setName(String name) {
78 this.name = name;
81 public String getDirection() {
82 return direction;
85 public void setMode(String mode) {
86 if ("null".equals(mode)) {
87 mode = null;
90 if (mode == null || mode.equals(MODE_VALUE_GEOSPATIAL)) {
91 this.mode = mode;
92 } else {
93 throw new AppEngineConfigException("Invalid mode: '" + mode);
97 public String getMode() {
98 return mode;
102 private List<Index> indexes;
104 public List<Index> getIndexes() {
105 return indexes;
108 public void setIndexes(List<Index> indexes) {
109 this.indexes = indexes;
112 public IndexesXml toXml(IndexesXml xml) {
113 if (xml == null) {
114 xml = new IndexesXml();
116 if (indexes != null) {
117 for (Index yamlIndex : indexes) {
118 if (yamlIndex.kind == null) {
119 throw new AppEngineConfigException("Index missing required element 'kind'");
121 IndexesXml.Index xmlIndex = xml.addNewIndex(yamlIndex.kind, yamlIndex.ancestor);
122 if (yamlIndex.properties != null) {
123 for (Property property : yamlIndex.properties) {
124 if (property.getName() == null) {
125 throw new AppEngineConfigException("Property is missing required element 'name'.");
127 xmlIndex.addNewProperty(
128 property.getName(), property.getDirection(), property.getMode());
133 return xml;
137 public static IndexesXml parse(Reader yaml, IndexesXml xml) {
138 List<IndexesXml> list;
139 try {
140 list = parseMultiple(yaml, xml);
141 } catch (YamlException ex) {
142 throw new AppEngineConfigException(ex.getMessage(), ex);
144 if (0 == list.size()) {
145 throw new AppEngineConfigException("Empty index configuration.");
147 if (list.size() > 1) {
148 throw new AppEngineConfigException(
149 "yaml unexepectedly contains more than one document: " + list.size());
151 return list.get(0);
155 * Parses the Yaml from {@code yaml} into a Yaml document and deserializes
156 * the document into an instance of {@link IndexesXml}.
157 * @param yaml A {@link String} from which to read the Yaml. This String is allowed to
158 * be in the style generated by the admin server, including the Python-specific tags.
159 * This method will safely ignore those tags.
160 * @return An instance of {@link IndexesXml}.
162 public static IndexesXml parse(String yaml) {
163 return parse(new StringReader(clean(yaml)), null);
167 * Parses the Yaml from {@code yaml} into one or more documents, and
168 * deserializes the documents into one or more instances of {@link IndexesXml}
169 * which are returned in a {@link List}.
171 * @param yaml A {@link String} from which to read the Yyaml. This String is
172 * allowed to be in the style generated by the admin server, including
173 * the Python-specific tags. This method will safely ignore those tags.
174 * @return A {@link List} of {@link IndexesXml} instances representing one or
175 * more parsed Yaml documents.
177 public static List<IndexesXml> parseMultiple(String yaml) {
178 try {
179 return parseMultiple(new StringReader(clean(yaml)), null);
180 } catch (YamlException ex) {
181 throw new AppEngineConfigException(ex.getMessage(), ex);
186 * Cleans a Yaml String by removing Pyton-specific tags.
187 * These tags are written by the admin server when it generates
188 * Yaml representing indexes.
189 * @param yaml A {@link String} containing Yaml
190 * @return The cleaned {@link String}
192 private static String clean(String yaml) {
193 return yaml
194 .replaceAll(INDEX_DEFINITIONS_TAG, "")
195 .replaceAll(INDEX_TAG, "")
196 .replaceAll(PROPERTY_TAG, "")
197 .trim();
201 * Parses the Yaml from {@code yaml} into one or more documents, and
202 * deserializes the documents into one or more instances of {@link IndexesXml}
203 * which are returned in a {@link List}.
205 * @param yaml A {@link Reader} from which to read the yaml
206 * @param xml A possibly {@code null} {@link IndexesXml} instance. If this
207 * parameter is not {@code null} then each of the yaml documents will
208 * be deserialized into it. This parameter is intended to be
209 * used in cases where there is only one Yaml document expected and so
210 * there will only be one instance of {@link IndexesXml} in the
211 * returned {@link List}. If this parameter is not {@code null} and the
212 * returned list has length greater than 1, then the list will contain
213 * multiple copies of this parameter.
214 * @return A {@link List} of {@link IndexesXml} instances representing one or
215 * more parsed Yaml documents.
216 * @throws YamlException If the Yaml parser has trouble parsing.
218 private static List<IndexesXml> parseMultiple(Reader yaml, IndexesXml xml) throws YamlException {
219 YamlReader reader = new YamlReader(yaml);
220 reader.getConfig().setPropertyElementType(IndexYaml.class, "indexes", IndexYaml.Index.class);
221 reader.getConfig().setPropertyElementType(
222 IndexYaml.Index.class, "properties", IndexYaml.Property.class);
223 List<IndexesXml> list = new LinkedList<IndexesXml>();
224 while (true) {
225 IndexYaml indexYaml = reader.read(IndexYaml.class);
226 if (null == indexYaml) {
227 break;
228 } else {
229 list.add(indexYaml.toXml(xml));
232 return list;