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
;
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";
31 * Wrapper around IndexesXml to make the JavaBeans properties match the YAML
34 public static class IndexYaml
{
36 public String application
;
38 * JavaBean wrapper for Index entries in IndexesXml.
40 public static class Index
{
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() {
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
;
67 throw new AppEngineConfigException(
68 "Invalid direction '" + direction
+ "': expected '" + DIRECTION_VALUE_ASC
69 + "' or '" + DIRECTION_VALUE_DESC
+ "'.");
73 public String
getName() {
77 public void setName(String name
) {
81 public String
getDirection() {
85 public void setMode(String mode
) {
86 if ("null".equals(mode
)) {
90 if (mode
== null || mode
.equals(MODE_VALUE_GEOSPATIAL
)) {
93 throw new AppEngineConfigException("Invalid mode: '" + mode
);
97 public String
getMode() {
102 private List
<Index
> indexes
;
104 public List
<Index
> getIndexes() {
108 public void setIndexes(List
<Index
> indexes
) {
109 this.indexes
= indexes
;
112 public IndexesXml
toXml(IndexesXml xml
) {
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());
137 public static IndexesXml
parse(Reader yaml
, IndexesXml xml
) {
138 List
<IndexesXml
> list
;
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());
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
) {
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
) {
194 .replaceAll(INDEX_DEFINITIONS_TAG
, "")
195 .replaceAll(INDEX_TAG
, "")
196 .replaceAll(PROPERTY_TAG
, "")
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
>();
225 IndexYaml indexYaml
= reader
.read(IndexYaml
.class);
226 if (null == indexYaml
) {
229 list
.add(indexYaml
.toXml(xml
));