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 "License"); 007 * you may not use this file except in compliance with the License. 008 * 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 /* 019 * $Id: Message.java 468650 2006-10-28 07:03:30Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.compiler; 023 024 import org.apache.bcel.generic.ConstantPoolGen; 025 import org.apache.bcel.generic.INVOKEINTERFACE; 026 import org.apache.bcel.generic.INVOKESPECIAL; 027 import org.apache.bcel.generic.INVOKEVIRTUAL; 028 import org.apache.bcel.generic.InstructionList; 029 import org.apache.bcel.generic.NEW; 030 import org.apache.bcel.generic.PUSH; 031 import org.apache.xalan.xsltc.compiler.util.ClassGenerator; 032 import org.apache.xalan.xsltc.compiler.util.MethodGenerator; 033 import org.apache.xalan.xsltc.compiler.util.Type; 034 import org.apache.xalan.xsltc.compiler.util.TypeCheckError; 035 036 /** 037 * @author Jacek Ambroziak 038 * @author Santiago Pericas-Geertsen 039 * @author Morten Jorgensen 040 */ 041 final class Message extends Instruction { 042 private boolean _terminate = false; 043 044 public void parseContents(Parser parser) { 045 String termstr = getAttribute("terminate"); 046 if (termstr != null) { 047 _terminate = termstr.equals("yes"); 048 } 049 parseChildren(parser); 050 } 051 052 public Type typeCheck(SymbolTable stable) throws TypeCheckError { 053 typeCheckContents(stable); 054 return Type.Void; 055 } 056 057 public void translate(ClassGenerator classGen, MethodGenerator methodGen) { 058 final ConstantPoolGen cpg = classGen.getConstantPool(); 059 final InstructionList il = methodGen.getInstructionList(); 060 061 // Load the translet (for call to displayMessage() function) 062 il.append(classGen.loadTranslet()); 063 064 switch (elementCount()) { 065 case 0: 066 il.append(new PUSH(cpg, "")); 067 break; 068 case 1: 069 SyntaxTreeNode child = (SyntaxTreeNode) elementAt(0); 070 if (child instanceof Text) { 071 il.append(new PUSH(cpg, ((Text) child).getText())); 072 break; 073 } 074 // falls through 075 default: 076 // Push current output handler onto the stack 077 il.append(methodGen.loadHandler()); 078 079 // Replace the current output handler by a ToXMLStream 080 il.append(new NEW(cpg.addClass(STREAM_XML_OUTPUT))); 081 il.append(methodGen.storeHandler()); 082 083 // Push a reference to a StringWriter 084 il.append(new NEW(cpg.addClass(STRING_WRITER))); 085 il.append(DUP); 086 il.append(DUP); 087 il.append(new INVOKESPECIAL( 088 cpg.addMethodref(STRING_WRITER, "<init>", "()V"))); 089 090 // Load ToXMLStream 091 il.append(methodGen.loadHandler()); 092 il.append(new INVOKESPECIAL( 093 cpg.addMethodref(STREAM_XML_OUTPUT, "<init>", 094 "()V"))); 095 096 // Invoke output.setWriter(STRING_WRITER) 097 il.append(methodGen.loadHandler()); 098 il.append(SWAP); 099 il.append(new INVOKEINTERFACE( 100 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 101 "setWriter", 102 "("+WRITER_SIG+")V"), 2)); 103 104 // Invoke output.setEncoding("UTF-8") 105 il.append(methodGen.loadHandler()); 106 il.append(new PUSH(cpg, "UTF-8")); // other encodings? 107 il.append(new INVOKEINTERFACE( 108 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 109 "setEncoding", 110 "("+STRING_SIG+")V"), 2)); 111 112 // Invoke output.setOmitXMLDeclaration(true) 113 il.append(methodGen.loadHandler()); 114 il.append(ICONST_1); 115 il.append(new INVOKEINTERFACE( 116 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 117 "setOmitXMLDeclaration", 118 "(Z)V"), 2)); 119 120 il.append(methodGen.loadHandler()); 121 il.append(new INVOKEINTERFACE( 122 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 123 "startDocument", 124 "()V"), 1)); 125 126 // Inline translation of contents 127 translateContents(classGen, methodGen); 128 129 il.append(methodGen.loadHandler()); 130 il.append(new INVOKEINTERFACE( 131 cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, 132 "endDocument", 133 "()V"), 1)); 134 135 // Call toString() on StringWriter 136 il.append(new INVOKEVIRTUAL( 137 cpg.addMethodref(STRING_WRITER, "toString", 138 "()" + STRING_SIG))); 139 140 // Restore old output handler 141 il.append(SWAP); 142 il.append(methodGen.storeHandler()); 143 break; 144 } 145 146 // Send the resulting string to the message handling method 147 il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS, 148 "displayMessage", 149 "("+STRING_SIG+")V"))); 150 151 // If 'terminate' attribute is set to 'yes': Instanciate a 152 // RunTimeException, but it on the stack and throw an exception 153 if (_terminate == true) { 154 // Create a new instance of RunTimeException 155 final int einit = cpg.addMethodref("java.lang.RuntimeException", 156 "<init>", 157 "(Ljava/lang/String;)V"); 158 il.append(new NEW(cpg.addClass("java.lang.RuntimeException"))); 159 il.append(DUP); 160 il.append(new PUSH(cpg,"Termination forced by an " + 161 "xsl:message instruction")); 162 il.append(new INVOKESPECIAL(einit)); 163 il.append(ATHROW); 164 } 165 } 166 167 }