001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.oozie.coord.input.logic; 020 021import java.util.List; 022 023import org.apache.commons.lang.StringUtils; 024import org.jdom.Element; 025import org.jdom.Namespace; 026 027/** 028 * Parses xml into jexl expression 029 */ 030public class InputLogicParser { 031 032 public final static String COORD_INPUT_EVENTS_DATA_IN = "data-in"; 033 034 public final static String AND = "and"; 035 036 public final static String OR = "or"; 037 038 public final static String COMBINE = "combine"; 039 040 /** 041 * Parses the xml. 042 * 043 * @param root the root 044 * @return the string 045 */ 046 public String parse(Element root) { 047 return parseWithName(root, null); 048 049 } 050 051 /** 052 * Parses the xml with name. 053 * 054 * @param root the root 055 * @param name the name 056 * @return the string 057 */ 058 @SuppressWarnings("unchecked") 059 public String parseWithName(Element root, String name) { 060 if (root == null) { 061 return ""; 062 } 063 StringBuffer parsedString = new StringBuffer(); 064 065 List<Element> childrens = root.getChildren(); 066 for (int i = 0; i < childrens.size(); i++) { 067 String childName = childrens.get(i).getAttributeValue("name"); 068 String min = childrens.get(i).getAttributeValue("min"); 069 String wait = childrens.get(i).getAttributeValue("wait"); 070 071 if (name == null || name.equals(childName)) { 072 parsedString.append(parse(childrens.get(i), getOpt(childrens.get(i).getName()), min, wait)); 073 } 074 else { 075 parsedString.append(parseWithName(childrens.get(i), name)); 076 } 077 } 078 return parsedString.toString(); 079 } 080 081 public String parse(Element root, String opt, String min, String wait) { 082 StringBuffer parsedString = new StringBuffer(); 083 084 Namespace ns = root.getNamespace(); 085 if (root.getName().equals(COMBINE)) { 086 parsedString.append("("); 087 parsedString.append(processCombinedNode(root, getOpt(root.getName()), getMin(root, min), 088 getWait(root, wait))); 089 parsedString.append(")"); 090 } 091 else if (root.getName().equals(AND) || root.getName().equals(OR)) { 092 parsedString.append("("); 093 parsedString.append(parseAllChildren(root, opt, getOpt(root.getName()), getMin(root, min), 094 getWait(root, wait))); 095 parsedString.append(")"); 096 097 } 098 else if (root.getChild(COORD_INPUT_EVENTS_DATA_IN, ns) != null) { 099 parsedString.append("("); 100 parsedString.append(processChildNode(root, getOpt(root.getName()), getMin(root, min), getWait(root, wait))); 101 parsedString.append(")"); 102 } 103 else if (root.getName().equals(COORD_INPUT_EVENTS_DATA_IN)) { 104 parsedString.append(parseDataInNode(root, min, wait)); 105 106 } 107 return parsedString.toString(); 108 109 } 110 111 /** 112 * Parses the all children. 113 * 114 * @param root the root 115 * @param parentOpt the parent opt 116 * @param opt the opt 117 * @param min the min 118 * @param wait the wait 119 * @return the string 120 */ 121 @SuppressWarnings("unchecked") 122 private String parseAllChildren(Element root, String parentOpt, String opt, String min, String wait) { 123 StringBuffer parsedString = new StringBuffer(); 124 125 List<Element> childrens = root.getChildren(); 126 for (int i = 0; i < childrens.size(); i++) { 127 String currentMin = min; 128 String currentWait = wait; 129 String childMin = childrens.get(i).getAttributeValue("min"); 130 String childWait = childrens.get(i).getAttributeValue("wait"); 131 if (!StringUtils.isEmpty(childMin)) { 132 currentMin = childMin; 133 } 134 if (!StringUtils.isEmpty(childWait)) { 135 currentWait = childWait; 136 } 137 parsedString.append(parse(childrens.get(i), opt, currentMin, currentWait)); 138 if (i < childrens.size() - 1) { 139 if (!StringUtils.isEmpty(opt)) 140 parsedString.append(" " + opt + " "); 141 } 142 } 143 return parsedString.toString(); 144 145 } 146 147 /** 148 * Parses the data in node. 149 * 150 * @param root the root 151 * @param min the min 152 * @param wait the wait 153 * @return the string 154 */ 155 private String parseDataInNode(Element root, String min, String wait) { 156 StringBuffer parsedString = new StringBuffer(); 157 158 String nestedChildDataName = root.getAttributeValue("dataset"); 159 160 parsedString.append("dependencyBuilder.input(\"" + nestedChildDataName + "\")"); 161 appendMin(root, min, parsedString); 162 appendWait(root, wait, parsedString); 163 parsedString.append(".build()"); 164 return parsedString.toString(); 165 } 166 167 /** 168 * Process child node. 169 * 170 * @param root the root 171 * @param opt the opt 172 * @param min the min 173 * @param wait the wait 174 * @return the string 175 */ 176 @SuppressWarnings("unchecked") 177 private String processChildNode(final Element root, final String opt, final String min, final String wait) { 178 StringBuffer parsedString = new StringBuffer(); 179 180 Namespace ns = root.getNamespace(); 181 182 List<Element> childrens = root.getChildren(COORD_INPUT_EVENTS_DATA_IN, ns); 183 184 for (int i = 0; i < childrens.size(); i++) { 185 parsedString.append(parseDataInNode(childrens.get(i), min, wait)); 186 187 if (i < childrens.size() - 1) { 188 parsedString.append(" " + opt + " "); 189 } 190 } 191 return parsedString.toString(); 192 } 193 194 /** 195 * Process combined node. 196 * 197 * @param root the root 198 * @param opt the opt 199 * @param min the min 200 * @param wait the wait 201 * @return the string 202 */ 203 @SuppressWarnings("unchecked") 204 private String processCombinedNode(final Element root, final String opt, final String min, final String wait) { 205 StringBuffer parsedString = new StringBuffer(); 206 207 Namespace ns = root.getNamespace(); 208 209 List<Element> childrens = root.getChildren(COORD_INPUT_EVENTS_DATA_IN, ns); 210 parsedString.append("dependencyBuilder.combine("); 211 212 for (int i = 0; i < childrens.size(); i++) { 213 String nestedChildDataName = childrens.get(i).getAttributeValue("dataset"); 214 parsedString.append("\"" + nestedChildDataName + "\""); 215 if (i < childrens.size() - 1) { 216 parsedString.append(","); 217 } 218 } 219 parsedString.append(")"); 220 221 appendMin(root, min, parsedString); 222 appendWait(root, wait, parsedString); 223 parsedString.append(".build()"); 224 return parsedString.toString(); 225 226 } 227 228 /** 229 * Gets the opt. 230 * 231 * @param opt the opt 232 * @return the opt 233 */ 234 private String getOpt(String opt) { 235 if (opt.equalsIgnoreCase("or")) { 236 return "||"; 237 } 238 239 if (opt.equalsIgnoreCase("and")) { 240 return "&&"; 241 } 242 243 return ""; 244 245 } 246 247 /** 248 * Gets the min. 249 * 250 * @param root the root 251 * @param parentMin the parent min 252 * @return the min 253 */ 254 private String getMin(Element root, String parentMin) { 255 String min = root.getAttributeValue("min"); 256 if (StringUtils.isEmpty(min)) { 257 return parentMin; 258 } 259 return min; 260 261 } 262 263 /** 264 * Gets the wait. 265 * 266 * @param root the root 267 * @param parentWait the parent wait 268 * @return the wait 269 */ 270 private String getWait(Element root, String parentWait) { 271 String wait = root.getAttributeValue("wait"); 272 if (StringUtils.isEmpty(parentWait)) { 273 return parentWait; 274 } 275 return wait; 276 277 } 278 279 private void appendWait(final Element root, String wait, StringBuffer parsedString) { 280 String childWait = root.getAttributeValue("wait"); 281 if (!StringUtils.isEmpty(childWait)) { 282 parsedString.append(".inputWait(" + childWait + ")"); 283 284 } 285 else { 286 if (!StringUtils.isEmpty(wait)) { 287 parsedString.append(".inputWait(" + wait + ")"); 288 289 } 290 } 291 292 } 293 294 private void appendMin(final Element root, String min, StringBuffer parsedString) { 295 String childMin = root.getAttributeValue("min"); 296 297 if (!StringUtils.isEmpty(childMin)) { 298 parsedString.append(".min(" + childMin + ")"); 299 300 } 301 else { 302 if (!StringUtils.isEmpty(min)) { 303 parsedString.append(".min(" + min + ")"); 304 305 } 306 } 307 } 308 309}