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.exception.VelocityException; 24 import org.apache.velocity.runtime.RuntimeServices; 25 import org.apache.velocity.runtime.parser.ParseException; 26 import org.apache.velocity.runtime.parser.Token; 27 import org.apache.velocity.runtime.parser.node.Node; 28 import org.apache.velocity.util.StringUtils; 29 30 import java.io.Writer; 31 import java.util.ArrayList; 32 33 /** 34 * Break directive used for interrupting scopes. 35 * 36 * @author <a href="mailto:wyla@removethis.sci.fi">Jarkko Viinamaki</a> 37 * @author Nathan Bubna 38 * @version $Id$ 39 */ 40 public class Break extends Directive 41 { 42 private boolean scoped = false; 43 44 /** 45 * Return name of this directive. 46 * @return The name of this directive. 47 */ 48 @Override getName()49 public String getName() 50 { 51 return "break"; 52 } 53 54 /** 55 * Return type of this directive. 56 * @return The type of this directive. 57 */ 58 @Override getType()59 public int getType() 60 { 61 return LINE; 62 } 63 64 /** 65 * Since there is no processing of content, 66 * there is never a need for an internal scope. 67 */ 68 @Override isScopeProvided()69 public boolean isScopeProvided() 70 { 71 return false; 72 } 73 74 @Override init(RuntimeServices rs, InternalContextAdapter context, Node node)75 public void init(RuntimeServices rs, InternalContextAdapter context, Node node) 76 { 77 super.init(rs, context, node); 78 79 this.scoped = (node.jjtGetNumChildren() == 1); 80 } 81 82 /** 83 * This directive throws a StopCommand which signals either 84 * the nearest Scope or the specified scope to stop rendering 85 * its content. 86 * @return never, always throws a StopCommand or Exception 87 */ 88 @Override render(InternalContextAdapter context, Writer writer, Node node)89 public boolean render(InternalContextAdapter context, Writer writer, Node node) 90 { 91 if (!scoped) 92 { 93 throw new StopCommand(); 94 } 95 96 Object argument = node.jjtGetChild(0).value(context); 97 if (argument instanceof Scope) 98 { 99 ((Scope)argument).stop(); 100 throw new IllegalStateException("Scope.stop() failed to throw a StopCommand"); 101 } 102 else 103 { 104 throw new VelocityException(node.jjtGetChild(0).literal()+ 105 " is not a valid " + Scope.class.getName() + " instance at " 106 + StringUtils.formatFileString(this), 107 null, 108 rsvc.getLogContext().getStackTrace()); 109 } 110 } 111 112 /** 113 * Called by the parser to validate the argument types 114 */ 115 @Override checkArgs(ArrayList<Integer> argtypes, Token t, String templateName)116 public void checkArgs(ArrayList<Integer> argtypes, Token t, String templateName) 117 throws ParseException 118 { 119 if (argtypes.size() > 1) 120 { 121 throw new MacroParseException("The #break directive takes only a single, optional Scope argument", 122 templateName, t); 123 } 124 } 125 126 } 127