1 package org.apache.velocity.runtime.directive; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import org.apache.velocity.context.InternalContextAdapter; 23 import org.apache.velocity.runtime.RuntimeServices; 24 import org.apache.velocity.runtime.parser.ParseException; 25 import org.apache.velocity.runtime.parser.Token; 26 import org.apache.velocity.runtime.parser.node.Node; 27 28 import java.io.Writer; 29 import java.util.ArrayList; 30 31 /** 32 * This class implements the #stop directive which allows 33 * a user to stop the merging and rendering process. The #stop directive 34 * will accept a single message argument with info about the reason for 35 * stopping. 36 */ 37 public class Stop extends Directive 38 { 39 private static final StopCommand STOP_ALL = new StopCommand("StopCommand to exit merging") { 40 @Override 41 public synchronized Throwable fillInStackTrace() { 42 return this; 43 } 44 }; 45 46 private boolean hasMessage = false; 47 48 /** 49 * Return name of this directive. 50 * @return The name of this directive. 51 */ 52 @Override getName()53 public String getName() 54 { 55 return "stop"; 56 } 57 58 /** 59 * Return type of this directive. 60 * @return The type of this directive. 61 */ 62 @Override getType()63 public int getType() 64 { 65 return LINE; 66 } 67 68 /** 69 * Since there is no processing of content, 70 * there is never a need for an internal scope. 71 */ 72 @Override isScopeProvided()73 public boolean isScopeProvided() 74 { 75 return false; 76 } 77 78 @Override init(RuntimeServices rs, InternalContextAdapter context, Node node)79 public void init(RuntimeServices rs, InternalContextAdapter context, Node node) 80 { 81 super.init(rs, context, node); 82 83 hasMessage = (node.jjtGetNumChildren() == 1); 84 } 85 86 @Override render(InternalContextAdapter context, Writer writer, Node node)87 public boolean render(InternalContextAdapter context, Writer writer, Node node) 88 { 89 if (!hasMessage) 90 { 91 throw STOP_ALL; 92 } 93 94 Object argument = node.jjtGetChild(0).value(context); 95 96 // stop all and use specified message 97 throw new StopCommand(String.valueOf(argument)); 98 } 99 100 /** 101 * Called by the parser to check the argument types 102 */ 103 @Override checkArgs(ArrayList<Integer> argtypes, Token t, String templateName)104 public void checkArgs(ArrayList<Integer> argtypes, Token t, String templateName) 105 throws ParseException 106 { 107 int kids = argtypes.size(); 108 if (kids > 1) 109 { 110 throw new MacroParseException("The #stop directive only accepts a single message parameter", 111 templateName, t); 112 } 113 } 114 115 } 116