1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Nov 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xalan.internal.xsltc.compiler;
  23 
  24 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
  25 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
  26 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
  27 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
  28 import com.sun.org.apache.bcel.internal.generic.InstructionList;
  29 import com.sun.org.apache.bcel.internal.generic.NEW;
  30 import com.sun.org.apache.bcel.internal.generic.PUSH;
  31 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
  32 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
  33 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
  34 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
  35 
  36 /**
  37  * @author Jacek Ambroziak
  38  * @author Santiago Pericas-Geertsen
  39  * @author Morten Jorgensen
  40  */
  41 final class Message extends Instruction {
  42     private boolean _terminate = false;
  43 
  44     public void parseContents(Parser parser) {
  45         String termstr = getAttribute("terminate");
  46         if (termstr != null) {
  47             _terminate = termstr.equals("yes");
  48         }
  49         parseChildren(parser);
  50     }
  51 
  52     public Type typeCheck(SymbolTable stable) throws TypeCheckError {
  53         typeCheckContents(stable);
  54         return Type.Void;
  55     }
  56 
  57     @SuppressWarnings("fallthrough") // at default
  58     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
  59         final ConstantPoolGen cpg = classGen.getConstantPool();
  60         final InstructionList il = methodGen.getInstructionList();
  61 
  62         // Load the translet (for call to displayMessage() function)
  63         il.append(classGen.loadTranslet());
  64 
  65         switch (elementCount()) {
  66             case 0:
  67                 il.append(new PUSH(cpg, ""));
  68             break;
  69             case 1:
  70                 SyntaxTreeNode child = elementAt(0);
  71                 if (child instanceof Text) {
  72                     il.append(new PUSH(cpg, ((Text) child).getText()));
  73                     break;
  74                 }
  75                 // falls through
  76             default:
  77                 // Push current output handler onto the stack
  78                 il.append(methodGen.loadHandler());
  79 
  80                 // Replace the current output handler by a ToXMLStream
  81                 il.append(new NEW(cpg.addClass(STREAM_XML_OUTPUT)));
  82                 il.append(methodGen.storeHandler());
  83 
  84                 // Push a reference to a StringWriter
  85                 il.append(new NEW(cpg.addClass(STRING_WRITER)));
  86                 il.append(DUP);
  87                 il.append(DUP);
  88                 il.append(new INVOKESPECIAL(
  89                     cpg.addMethodref(STRING_WRITER, "<init>", "()V")));
  90 
  91                 // Load ToXMLStream
  92                 il.append(methodGen.loadHandler());
  93                 il.append(new INVOKESPECIAL(
  94                     cpg.addMethodref(STREAM_XML_OUTPUT, "<init>",
  95                                      "()V")));
  96 
  97                 // Invoke output.setWriter(STRING_WRITER)
  98                 il.append(methodGen.loadHandler());
  99                 il.append(SWAP);
 100                 il.append(new INVOKEINTERFACE(
 101                     cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
 102                                               "setWriter",
 103                                               "("+WRITER_SIG+")V"), 2));
 104 
 105                 // Invoke output.setEncoding("UTF-8")
 106                 il.append(methodGen.loadHandler());
 107                 il.append(new PUSH(cpg, "UTF-8"));   // other encodings?
 108                 il.append(new INVOKEINTERFACE(
 109                     cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
 110                                               "setEncoding",
 111                                               "("+STRING_SIG+")V"), 2));
 112 
 113                 // Invoke output.setOmitXMLDeclaration(true)
 114                 il.append(methodGen.loadHandler());
 115                 il.append(ICONST_1);
 116                 il.append(new INVOKEINTERFACE(
 117                     cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
 118                                               "setOmitXMLDeclaration",
 119                                               "(Z)V"), 2));
 120 
 121                 il.append(methodGen.loadHandler());
 122                 il.append(new INVOKEINTERFACE(
 123                     cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
 124                                               "startDocument",
 125                                               "()V"), 1));
 126 
 127                 // Inline translation of contents
 128                 translateContents(classGen, methodGen);
 129 
 130                 il.append(methodGen.loadHandler());
 131                 il.append(new INVOKEINTERFACE(
 132                     cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE,
 133                                               "endDocument",
 134                                               "()V"), 1));
 135 
 136                 // Call toString() on StringWriter
 137                 il.append(new INVOKEVIRTUAL(
 138                     cpg.addMethodref(STRING_WRITER, "toString",
 139                                      "()" + STRING_SIG)));
 140 
 141                 // Restore old output handler
 142                 il.append(SWAP);
 143                 il.append(methodGen.storeHandler());
 144             break;
 145         }
 146 
 147         // Send the resulting string to the message handling method
 148         il.append(new INVOKEVIRTUAL(cpg.addMethodref(TRANSLET_CLASS,
 149                                                      "displayMessage",
 150                                                      "("+STRING_SIG+")V")));
 151 
 152         // If 'terminate' attribute is set to 'yes': Instanciate a
 153         // RunTimeException, but it on the stack and throw an exception
 154         if (_terminate == true) {
 155             // Create a new instance of RunTimeException
 156             final int einit = cpg.addMethodref("java.lang.RuntimeException",
 157                                                "<init>",
 158                                                "(Ljava/lang/String;)V");
 159             il.append(new NEW(cpg.addClass("java.lang.RuntimeException")));
 160             il.append(DUP);
 161             il.append(new PUSH(cpg,"Termination forced by an " +
 162                                    "xsl:message instruction"));
 163             il.append(new INVOKESPECIAL(einit));
 164             il.append(ATHROW);
 165         }
 166     }
 167 
 168 }