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 }