1 /* 2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.beans.decoder; 26 27 /** 28 * The base class for element handlers. 29 * 30 * @since 1.7 31 * 32 * @author Sergey A. Malenkov 33 * 34 * @see DocumentHandler 35 */ 36 public abstract class ElementHandler { 37 private DocumentHandler owner; 38 private ElementHandler parent; 39 40 private String id; 41 42 /** 43 * Returns the document handler that creates this element handler. 44 * 45 * @return the owner document handler 46 */ getOwner()47 public final DocumentHandler getOwner() { 48 return this.owner; 49 } 50 51 /** 52 * Sets the document handler that creates this element handler. 53 * The owner document handler should be set after instantiation. 54 * Such approach is used to simplify the extensibility. 55 * 56 * @param owner the owner document handler 57 * @see DocumentHandler#startElement 58 */ setOwner(DocumentHandler owner)59 final void setOwner(DocumentHandler owner) { 60 if (owner == null) { 61 throw new IllegalArgumentException("Every element should have owner"); 62 } 63 this.owner = owner; 64 } 65 66 /** 67 * Returns the element handler that contains this one. 68 * 69 * @return the parent element handler 70 */ getParent()71 public final ElementHandler getParent() { 72 return this.parent; 73 } 74 75 /** 76 * Sets the element handler that contains this one. 77 * The parent element handler should be set after instantiation. 78 * Such approach is used to simplify the extensibility. 79 * 80 * @param parent the parent element handler 81 * @see DocumentHandler#startElement 82 */ setParent(ElementHandler parent)83 final void setParent(ElementHandler parent) { 84 this.parent = parent; 85 } 86 87 /** 88 * Returns the value of the variable with specified identifier. 89 * 90 * @param id the identifier 91 * @return the value of the variable 92 */ getVariable(String id)93 protected final Object getVariable(String id) { 94 if (id.equals(this.id)) { 95 ValueObject value = getValueObject(); 96 if (value.isVoid()) { 97 throw new IllegalStateException("The element does not return value"); 98 } 99 return value.getValue(); 100 } 101 return (this.parent != null) 102 ? this.parent.getVariable(id) 103 : this.owner.getVariable(id); 104 } 105 106 /** 107 * Returns the value of the parent element. 108 * 109 * @return the value of the parent element 110 */ getContextBean()111 protected Object getContextBean() { 112 if (this.parent != null) { 113 ValueObject value = this.parent.getValueObject(); 114 if (!value.isVoid()) { 115 return value.getValue(); 116 } 117 throw new IllegalStateException("The outer element does not return value"); 118 } else { 119 Object value = this.owner.getOwner(); 120 if (value != null) { 121 return value; 122 } 123 throw new IllegalStateException("The topmost element does not have context"); 124 } 125 } 126 127 /** 128 * Parses attributes of the element. 129 * By default, the following attribute is supported: 130 * <dl> 131 * <dt>id 132 * <dd>the identifier of the variable that is intended to store the result 133 * </dl> 134 * 135 * @param name the attribute name 136 * @param value the attribute value 137 */ addAttribute(String name, String value)138 public void addAttribute(String name, String value) { 139 if (name.equals("id")) { // NON-NLS: the attribute name 140 this.id = value; 141 } else { 142 throw new IllegalArgumentException("Unsupported attribute: " + name); 143 } 144 } 145 146 /** 147 * This method is called before parsing of the element's body. 148 * All attributes are parsed at this point. 149 * By default, do nothing. 150 */ startElement()151 public void startElement() { 152 } 153 154 /** 155 * This method is called after parsing of the element's body. 156 * By default, it calculates the value of this element. 157 * The following tasks are executing for any non-void value: 158 * <ol> 159 * <li>If the {@code id} attribute is set 160 * the value of the variable with the specified identifier 161 * is set to the value of this element.</li> 162 * <li>This element is used as an argument of parent element if it is possible.</li> 163 * </ol> 164 * 165 * @see #isArgument 166 */ endElement()167 public void endElement() { 168 // do nothing if no value returned 169 ValueObject value = getValueObject(); 170 if (!value.isVoid()) { 171 if (this.id != null) { 172 this.owner.setVariable(this.id, value.getValue()); 173 } 174 if (isArgument()) { 175 if (this.parent != null) { 176 this.parent.addArgument(value.getValue()); 177 } else { 178 this.owner.addObject(value.getValue()); 179 } 180 } 181 } 182 } 183 184 /** 185 * Adds the character that contained in this element. 186 * By default, only whitespaces are acceptable. 187 * 188 * @param ch the character 189 */ addCharacter(char ch)190 public void addCharacter(char ch) { 191 if ((ch != ' ') && (ch != '\n') && (ch != '\t') && (ch != '\r')) { 192 throw new IllegalStateException("Illegal character with code " + (int) ch); 193 } 194 } 195 196 /** 197 * Adds the argument that is used to calculate the value of this element. 198 * By default, no arguments are acceptable. 199 * 200 * @param argument the value of the element that contained in this one 201 */ addArgument(Object argument)202 protected void addArgument(Object argument) { 203 throw new IllegalStateException("Could not add argument to simple element"); 204 } 205 206 /** 207 * Tests whether the value of this element can be used 208 * as an argument of the element that contained in this one. 209 * 210 * @return {@code true} if the value of this element can be used 211 * as an argument of the element that contained in this one, 212 * {@code false} otherwise 213 */ isArgument()214 protected boolean isArgument() { 215 return this.id == null; 216 } 217 218 /** 219 * Returns the value of this element. 220 * 221 * @return the value of this element 222 */ getValueObject()223 protected abstract ValueObject getValueObject(); 224 } 225