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 */ 018package org.apache.hadoop.fs.shell.find; 019 020import java.io.IOException; 021import java.util.Deque; 022import java.util.LinkedList; 023import java.util.List; 024 025import org.apache.hadoop.conf.Configurable; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.fs.FileStatus; 028import org.apache.hadoop.fs.FileSystem; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.fs.shell.PathData; 031 032/** 033 * Abstract expression for use in the 034 * {@link org.apache.hadoop.fs.shell.find.Find} command. Provides default 035 * behavior for a no-argument primary expression. 036 */ 037public abstract class BaseExpression implements Expression, Configurable { 038 private String[] usage = { "Not yet implemented" }; 039 private String[] help = { "Not yet implemented" }; 040 041 /** Sets the usage text for this {@link Expression} */ 042 protected void setUsage(String[] usage) { 043 this.usage = usage; 044 } 045 046 /** Sets the help text for this {@link Expression} */ 047 protected void setHelp(String[] help) { 048 this.help = help; 049 } 050 051 @Override 052 public String[] getUsage() { 053 return this.usage; 054 } 055 056 @Override 057 public String[] getHelp() { 058 return this.help; 059 } 060 061 @Override 062 public void setOptions(FindOptions options) throws IOException { 063 this.options = options; 064 for (Expression child : getChildren()) { 065 child.setOptions(options); 066 } 067 } 068 069 @Override 070 public void prepare() throws IOException { 071 for (Expression child : getChildren()) { 072 child.prepare(); 073 } 074 } 075 076 @Override 077 public void finish() throws IOException { 078 for (Expression child : getChildren()) { 079 child.finish(); 080 } 081 } 082 083 /** Options passed in from the {@link Find} command. */ 084 private FindOptions options; 085 086 /** Hadoop configuration. */ 087 private Configuration conf; 088 089 /** Arguments for this expression. */ 090 private LinkedList<String> arguments = new LinkedList<String>(); 091 092 /** Children of this expression. */ 093 private LinkedList<Expression> children = new LinkedList<Expression>(); 094 095 /** Return the options to be used by this expression. */ 096 protected FindOptions getOptions() { 097 return (this.options == null) ? new FindOptions() : this.options; 098 } 099 100 @Override 101 public void setConf(Configuration conf) { 102 this.conf = conf; 103 } 104 105 @Override 106 public Configuration getConf() { 107 return this.conf; 108 } 109 110 @Override 111 public String toString() { 112 StringBuilder sb = new StringBuilder(); 113 sb.append(getClass().getSimpleName()); 114 sb.append("("); 115 boolean firstArg = true; 116 for (String arg : getArguments()) { 117 if (!firstArg) { 118 sb.append(","); 119 } else { 120 firstArg = false; 121 } 122 sb.append(arg); 123 } 124 sb.append(";"); 125 firstArg = true; 126 for (Expression child : getChildren()) { 127 if (!firstArg) { 128 sb.append(","); 129 } else { 130 firstArg = false; 131 } 132 sb.append(child.toString()); 133 } 134 sb.append(")"); 135 return sb.toString(); 136 } 137 138 @Override 139 public boolean isAction() { 140 for (Expression child : getChildren()) { 141 if (child.isAction()) { 142 return true; 143 } 144 } 145 return false; 146 } 147 148 @Override 149 public boolean isOperator() { 150 return false; 151 } 152 153 /** 154 * Returns the arguments of this expression 155 * 156 * @return list of argument strings 157 */ 158 protected List<String> getArguments() { 159 return this.arguments; 160 } 161 162 /** 163 * Returns the argument at the given position (starting from 1). 164 * 165 * @param position 166 * argument to be returned 167 * @return requested argument 168 * @throws IOException 169 * if the argument doesn't exist or is null 170 */ 171 protected String getArgument(int position) throws IOException { 172 if (position > this.arguments.size()) { 173 throw new IOException("Missing argument at " + position); 174 } 175 String argument = this.arguments.get(position - 1); 176 if (argument == null) { 177 throw new IOException("Null argument at position " + position); 178 } 179 return argument; 180 } 181 182 /** 183 * Returns the children of this expression. 184 * 185 * @return list of child expressions 186 */ 187 protected List<Expression> getChildren() { 188 return this.children; 189 } 190 191 @Override 192 public int getPrecedence() { 193 return 0; 194 } 195 196 @Override 197 public void addChildren(Deque<Expression> exprs) { 198 // no children by default, will be overridden by specific expressions. 199 } 200 201 /** 202 * Add a specific number of children to this expression. The children are 203 * popped off the head of the expressions. 204 * 205 * @param exprs 206 * deque of expressions from which to take the children 207 * @param count 208 * number of children to be added 209 */ 210 protected void addChildren(Deque<Expression> exprs, int count) { 211 for (int i = 0; i < count; i++) { 212 addChild(exprs.pop()); 213 } 214 } 215 216 /** 217 * Add a single argument to this expression. The argument is popped off the 218 * head of the expressions. 219 * 220 * @param expr 221 * child to add to the expression 222 */ 223 private void addChild(Expression expr) { 224 children.push(expr); 225 } 226 227 @Override 228 public void addArguments(Deque<String> args) { 229 // no children by default, will be overridden by specific expressions. 230 } 231 232 /** 233 * Add a specific number of arguments to this expression. The children are 234 * popped off the head of the expressions. 235 * 236 * @param args 237 * deque of arguments from which to take the argument 238 * @param count 239 * number of children to be added 240 */ 241 protected void addArguments(Deque<String> args, int count) { 242 for (int i = 0; i < count; i++) { 243 addArgument(args.pop()); 244 } 245 } 246 247 /** 248 * Add a single argument to this expression. The argument is popped off the 249 * head of the expressions. 250 * 251 * @param arg 252 * argument to add to the expression 253 */ 254 protected void addArgument(String arg) { 255 arguments.add(arg); 256 } 257 258 /** 259 * Returns the {@link FileStatus} from the {@link PathData} item. If the 260 * current options require links to be followed then the returned file status 261 * is that of the linked file. 262 * 263 * @param item 264 * PathData 265 * @param depth 266 * current depth in the process directories 267 * @return FileStatus 268 */ 269 protected FileStatus getFileStatus(PathData item, int depth) 270 throws IOException { 271 FileStatus fileStatus = item.stat; 272 if (fileStatus.isSymlink()) { 273 if (options.isFollowLink() || (options.isFollowArgLink() && 274 (depth == 0))) { 275 Path linkedFile = item.fs.resolvePath(fileStatus.getSymlink()); 276 fileStatus = getFileSystem(item).getFileStatus(linkedFile); 277 } 278 } 279 return fileStatus; 280 } 281 282 /** 283 * Returns the {@link Path} from the {@link PathData} item. 284 * 285 * @param item 286 * PathData 287 * @return Path 288 */ 289 protected Path getPath(PathData item) throws IOException { 290 return item.path; 291 } 292 293 /** 294 * Returns the {@link FileSystem} associated with the {@link PathData} item. 295 * 296 * @param item PathData 297 * @return FileSystem 298 */ 299 protected FileSystem getFileSystem(PathData item) throws IOException { 300 return item.fs; 301 } 302}