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    }