App Engine Python SDK version 1.8.4
[gae.git] / java / src / main / com / google / apphosting / utils / config / IndexYamlReader.java
blob69cc46d0ca7ccf99554cd0cb4d1cbabddcc83191
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.apphosting.utils.config;
5 import net.sourceforge.yamlbeans.YamlException;
6 import net.sourceforge.yamlbeans.YamlReader;
8 import java.io.Reader;
9 import java.io.StringReader;
10 import java.util.LinkedList;
11 import java.util.List;
13 /**
14 * Class to parse index.yaml into a IndexesXml object.
17 public class IndexYamlReader {
19 public static final String INDEX_DEFINITIONS_TAG =
20 "!!python/object:google.appengine.datastore.datastore_index.IndexDefinitions";
21 public static final String INDEX_TAG =
22 "!!python/object:google.appengine.datastore.datastore_index.Index";
23 public static final String PROPERTY_TAG =
24 "!!python/object:google.appengine.datastore.datastore_index.Property";
26 /**
27 * Wrapper around IndexesXml to make the JavaBeans properties match the YAML
28 * file syntax.
30 public static class IndexYaml {
32 /**
33 * JavaBean wrapper for Index entries in IndexesXml.
35 public static class Index {
36 public String kind;
37 protected boolean ancestor;
38 public List<Property> properties;
40 public void setAncestor(String ancestor) {
41 this.ancestor = YamlUtils.parseBoolean(ancestor);
44 public String getAncestor() {
45 return "" + ancestor;
49 /**
50 * JavaBean wrapper for IndexesXml properties.
52 public static class Property {
53 public String name;
54 private String direction = "asc";
56 public void setDirection(String direction) {
57 if ("desc".equals(direction) || "asc".equals(direction)) {
58 this.direction = direction;
59 } else {
60 throw new AppEngineConfigException(
61 "Invalid direction '" + direction + "': expected 'asc' or 'desc'.");
65 public String getDirection() {
66 return direction;
69 public boolean isAscending() {
70 return "asc".equals(direction);
74 private List<Index> indexes;
76 public List<Index> getIndexes() {
77 return indexes;
80 public void setIndexes(List<Index> indexes) {
81 this.indexes = indexes;
84 public IndexesXml toXml(IndexesXml xml) {
85 if (indexes == null) {
86 throw new AppEngineConfigException("Empty index configuration.");
88 if (xml == null) {
89 xml = new IndexesXml();
91 for (Index yamlIndex : indexes) {
92 if (yamlIndex.kind == null) {
93 throw new AppEngineConfigException("Index missing required element 'kind'");
95 IndexesXml.Index xmlIndex = xml.addNewIndex(yamlIndex.kind, yamlIndex.ancestor);
96 if (yamlIndex.properties != null) {
97 for (Property property : yamlIndex.properties) {
98 if (property.name == null) {
99 throw new AppEngineConfigException("Property is missing required element 'name'.");
101 xmlIndex.addNewProperty(property.name, property.isAscending());
105 return xml;
109 public static IndexesXml parse(Reader yaml, IndexesXml xml) {
110 List<IndexesXml> list;
111 try {
112 list = parseMultiple(yaml, xml);
113 } catch (YamlException ex) {
114 throw new AppEngineConfigException(ex.getMessage(), ex);
116 if (0 == list.size()) {
117 throw new AppEngineConfigException("Empty index configuration.");
119 if (list.size() > 1) {
120 throw new AppEngineConfigException(
121 "yaml unexepectedly contains more than one document: " + list.size());
123 return list.get(0);
127 * Parses the Yaml from {@code yaml} into a Yaml document and deserializes
128 * the document into an instance of {@link IndexesXml}.
129 * @param yaml A {@link String} from which to read the Yaml. This String is allowed to
130 * be in the style generated by the admin server, including the Python-specific tags.
131 * This method will safely ignore those tags.
132 * @return An instance of {@link IndexesXml}.
134 public static IndexesXml parse(String yaml) {
135 return parse(new StringReader(clean(yaml)), null);
139 * Parses the Yaml from {@code yaml} into one or more documents, and
140 * deserializes the documents into one or more instances of {@link IndexesXml}
141 * which are returned in a {@link List}.
143 * @param yaml A {@link String} from which to read the Yyaml. This String is
144 * allowed to be in the style generated by the admin server, including
145 * the Python-specific tags. This method will safely ignore those tags.
146 * @return A {@link List} of {@link IndexesXml} instances representing one or
147 * more parsed Yaml documents.
149 public static List<IndexesXml> parseMultiple(String yaml) {
150 try {
151 return parseMultiple(new StringReader(clean(yaml)), null);
152 } catch (YamlException ex) {
153 throw new AppEngineConfigException(ex.getMessage(), ex);
158 * Cleans a Yaml String by removing Pyton-specific tags.
159 * These tags are written by the admin server when it generates
160 * Yaml representing indexes.
161 * @param yaml A {@link String} containing Yaml
162 * @return The cleaned {@link String}
164 private static String clean(String yaml) {
165 return yaml
166 .replaceAll(INDEX_DEFINITIONS_TAG, "")
167 .replaceAll(INDEX_TAG, "")
168 .replaceAll(PROPERTY_TAG, "")
169 .trim();
173 * Parses the Yaml from {@code yaml} into one or more documents, and
174 * deserializes the documents into one or more instances of {@link IndexesXml}
175 * which are returned in a {@link List}.
177 * @param yaml A {@link Reader} from which to read the yaml
178 * @param xml A possibly {@code null} {@link IndexesXml} instance. If this
179 * parameter is not {@code null} then each of the yaml documents will
180 * be deserialized into it. This parameter is intended to be
181 * used in cases where there is only one Yaml document expected and so
182 * there will only be one instance of {@link IndexesXml} in the
183 * returned {@link List}. If this parameter is not {@code null} and the
184 * returned list has length greater than 1, then the list will contain
185 * multiple copies of this parameter.
186 * @return A {@link List} of {@link IndexesXml} instances representing one or
187 * more parsed Yaml documents.
188 * @throws YamlException If the Yaml parser has trobule parsing.
190 private static List<IndexesXml> parseMultiple(Reader yaml, IndexesXml xml) throws YamlException {
191 YamlReader reader = new YamlReader(yaml);
192 reader.getConfig().setPropertyElementType(IndexYaml.class, "indexes", IndexYaml.Index.class);
193 reader.getConfig().setPropertyElementType(
194 IndexYaml.Index.class, "properties", IndexYaml.Property.class);
195 List<IndexesXml> list = new LinkedList<IndexesXml>();
196 while (true) {
197 IndexYaml indexYaml = reader.read(IndexYaml.class);
198 if (null == indexYaml) {
199 break;
200 } else {
201 list.add(indexYaml.toXml(xml));
204 return list;