App Engine Java SDK version 1.9.25
[gae.git] / java / src / main / com / google / apphosting / utils / config / CronXmlReader.java
blob8610488aa687a2d8bb17ad323bdf187be39672e0
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 package com.google.apphosting.utils.config;
4 import org.mortbay.xml.XmlParser.Node;
6 import java.io.InputStream;
7 import java.util.Stack;
9 /**
10 * Creates an {@link CronXml} instance from
11 * <appdir>WEB-INF/cron.xml. If you want to read the configuration
12 * from a different file, subclass and override {@link #getFilename()}. If you
13 * want to read the configuration from something that isn't a file, subclass
14 * and override {@link #getInputStream()}.
17 public class CronXmlReader extends AbstractConfigXmlReader<CronXml> {
19 private static final String FILENAME = "WEB-INF/cron.xml";
21 private static final String CRONENTRIES_TAG = "cronentries";
22 private static final String CRON_TAG = "cron";
23 private static final String DESCRIPTION_TAG = "description";
24 private static final String SCHEDULE_TAG = "schedule";
25 private static final String TARGET_TAG = "target";
26 private static final String TIMEZONE_TAG = "timezone";
27 private static final String URL_TAG = "url";
28 private static final String RETRY_PARAMETERS_TAG = "retry-parameters";
29 private static final String JOB_RETRY_LIMIT_TAG = "job-retry-limit";
30 private static final String JOB_AGE_LIMIT_TAG = "job-age-limit";
31 private static final String MIN_BACKOFF_SECONDS_TAG = "min-backoff-seconds";
32 private static final String MAX_BACKOFF_SECONDS_TAG = "max-backoff-seconds";
33 private static final String MAX_DOUBLINGS_TAG = "max-doublings";
35 /**
36 * Constructs the reader for {@code cron.xml} in a given application directory.
37 * @param appDir the application directory
39 public CronXmlReader(String appDir) {
40 super(appDir, false);
43 /**
44 * Parses the config file.
45 * @return A {@link CronXml} object representing the parsed configuration.
47 public CronXml readCronXml() {
48 return readConfigXml();
51 @Override
52 protected CronXml processXml(InputStream is) {
53 final CronXml cronXml = new CronXml();
54 parse(new ParserCallback() {
55 boolean first = true;
56 CronXml.Entry entry;
57 boolean insideRetryParametersTag = false;
59 @Override
60 public void newNode(Node node, Stack<Node> ancestors) {
61 switch (ancestors.size()) {
62 case 0:
63 if (!CRONENTRIES_TAG.equalsIgnoreCase(node.getTag())) {
64 throw new AppEngineConfigException(getFilename() + " does not contain <"
65 + CRONENTRIES_TAG + ">");
67 if (!first) {
68 throw new AppEngineConfigException(getFilename() + " contains multiple <"
69 + CRONENTRIES_TAG + ">");
71 first = false;
72 break;
74 case 1:
75 if (CRON_TAG.equalsIgnoreCase(node.getTag())) {
76 entry = cronXml.addNewEntry();
77 } else {
78 throw new AppEngineConfigException(getFilename() + " contains <"
79 + node.getTag() + "> instead of <" + CRON_TAG + "/>");
81 break;
83 case 2:
84 insideRetryParametersTag = false;
85 assert(entry != null);
86 if (DESCRIPTION_TAG.equalsIgnoreCase(node.getTag())) {
87 if (node.size() == 1 && node.get(0) instanceof String) {
88 entry.setDescription((String) node.get(0));
89 } else {
90 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
91 + DESCRIPTION_TAG + ">");
93 } else if (URL_TAG.equalsIgnoreCase(node.getTag())) {
94 if (node.size() == 1 && node.get(0) instanceof String) {
95 entry.setUrl((String) node.get(0));
96 } else {
97 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
98 + URL_TAG + ">");
100 } else if (SCHEDULE_TAG.equalsIgnoreCase(node.getTag())) {
101 if (node.size() == 1 && node.get(0) instanceof String) {
102 entry.setSchedule((String) node.get(0));
103 } else {
104 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
105 + SCHEDULE_TAG + ">");
107 } else if (TIMEZONE_TAG.equalsIgnoreCase(node.getTag())) {
108 if (node.size() == 1 && node.get(0) instanceof String) {
109 entry.setTimezone((String) node.get(0));
110 } else {
111 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
112 + TIMEZONE_TAG + ">");
114 } else if (TARGET_TAG.equalsIgnoreCase(node.getTag())) {
115 if (node.size() == 1 && node.get(0) instanceof String) {
116 entry.setTarget((String) node.get(0));
117 } else {
118 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
119 + TARGET_TAG + ">");
121 } else if (RETRY_PARAMETERS_TAG.equalsIgnoreCase(node.getTag())) {
122 entry.setRetryParameters(new RetryParametersXml());
123 insideRetryParametersTag = true;
124 } else {
125 throw new AppEngineConfigException(getFilename() + " contains unknown <"
126 + node.getTag() + "> inside <" + CRON_TAG + "/>");
128 break;
130 case 3:
131 assert(insideRetryParametersTag);
132 assert(entry != null);
133 boolean brokenTag = !(node.size() == 1 && node.get(0) instanceof String);
135 RetryParametersXml retryParameters = entry.getRetryParameters();
136 assert(entry.getRetryParameters() != null);
138 if (JOB_RETRY_LIMIT_TAG.equalsIgnoreCase(node.getTag())) {
139 if (!brokenTag) {
140 retryParameters.setRetryLimit(getString(node));
142 } else if (JOB_AGE_LIMIT_TAG.equalsIgnoreCase(node.getTag())) {
143 if (!brokenTag) {
144 retryParameters.setAgeLimitSec(getString(node));
146 } else if (MIN_BACKOFF_SECONDS_TAG.equalsIgnoreCase(node.getTag())) {
147 if (!brokenTag) {
148 retryParameters.setMinBackoffSec(getString(node));
150 } else if (MAX_BACKOFF_SECONDS_TAG.equalsIgnoreCase(node.getTag())) {
151 if (!brokenTag) {
152 retryParameters.setMaxBackoffSec(getString(node));
154 } else if (MAX_DOUBLINGS_TAG.equalsIgnoreCase(node.getTag())) {
155 if (!brokenTag) {
156 retryParameters.setMaxDoublings(getString(node));
158 } else {
159 throw new AppEngineConfigException(getFilename() + " contains unknown <"
160 + node.getTag() + "> inside <" + RETRY_PARAMETERS_TAG + "/>");
163 if (brokenTag) {
164 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
165 + node.getTag() + ">");
167 break;
169 default:
170 throw new AppEngineConfigException(getFilename()
171 + " has a syntax error; node <"
172 + node.getTag() + "> is too deeply nested to be valid.");
175 }, is);
176 cronXml.validateLastEntry();
177 return cronXml;
180 @Override
181 protected String getRelativeFilename() {
182 return FILENAME;