Path: blob/master/src/java.desktop/share/classes/com/sun/beans/decoder/DocumentHandler.java
41171 views
/*1* Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package com.sun.beans.decoder;2526import com.sun.beans.finder.ClassFinder;2728import java.beans.ExceptionListener;2930import java.io.IOException;31import java.io.StringReader;3233import java.lang.ref.Reference;34import java.lang.ref.WeakReference;3536import java.util.ArrayList;37import java.util.HashMap;38import java.util.List;39import java.util.Map;40import java.security.AccessControlContext;41import java.security.AccessController;42import java.security.PrivilegedAction;4344import javax.xml.parsers.ParserConfigurationException;45import javax.xml.parsers.SAXParserFactory;4647import org.xml.sax.Attributes;48import org.xml.sax.InputSource;49import org.xml.sax.SAXException;50import org.xml.sax.helpers.DefaultHandler;5152import jdk.internal.access.SharedSecrets;5354/**55* The main class to parse JavaBeans XML archive.56*57* @since 1.758*59* @author Sergey A. Malenkov60*61* @see ElementHandler62*/63public final class DocumentHandler extends DefaultHandler {64@SuppressWarnings("removal")65private final AccessControlContext acc = AccessController.getContext();66private final Map<String, Class<? extends ElementHandler>> handlers = new HashMap<>();67private final Map<String, Object> environment = new HashMap<>();68private final List<Object> objects = new ArrayList<>();6970private Reference<ClassLoader> loader;71private ExceptionListener listener;72private Object owner;7374private ElementHandler handler;7576/**77* Creates new instance of document handler.78*/79public DocumentHandler() {80setElementHandler("java", JavaElementHandler.class); // NON-NLS: the element name81setElementHandler("null", NullElementHandler.class); // NON-NLS: the element name82setElementHandler("array", ArrayElementHandler.class); // NON-NLS: the element name83setElementHandler("class", ClassElementHandler.class); // NON-NLS: the element name84setElementHandler("string", StringElementHandler.class); // NON-NLS: the element name85setElementHandler("object", ObjectElementHandler.class); // NON-NLS: the element name8687setElementHandler("void", VoidElementHandler.class); // NON-NLS: the element name88setElementHandler("char", CharElementHandler.class); // NON-NLS: the element name89setElementHandler("byte", ByteElementHandler.class); // NON-NLS: the element name90setElementHandler("short", ShortElementHandler.class); // NON-NLS: the element name91setElementHandler("int", IntElementHandler.class); // NON-NLS: the element name92setElementHandler("long", LongElementHandler.class); // NON-NLS: the element name93setElementHandler("float", FloatElementHandler.class); // NON-NLS: the element name94setElementHandler("double", DoubleElementHandler.class); // NON-NLS: the element name95setElementHandler("boolean", BooleanElementHandler.class); // NON-NLS: the element name9697// some handlers for new elements98setElementHandler("new", NewElementHandler.class); // NON-NLS: the element name99setElementHandler("var", VarElementHandler.class); // NON-NLS: the element name100setElementHandler("true", TrueElementHandler.class); // NON-NLS: the element name101setElementHandler("false", FalseElementHandler.class); // NON-NLS: the element name102setElementHandler("field", FieldElementHandler.class); // NON-NLS: the element name103setElementHandler("method", MethodElementHandler.class); // NON-NLS: the element name104setElementHandler("property", PropertyElementHandler.class); // NON-NLS: the element name105}106107/**108* Returns the class loader used to instantiate objects.109* If the class loader has not been explicitly set110* then {@code null} is returned.111*112* @return the class loader used to instantiate objects113*/114public ClassLoader getClassLoader() {115return (this.loader != null)116? this.loader.get()117: null;118}119120/**121* Sets the class loader used to instantiate objects.122* If the class loader is not set123* then default class loader will be used.124*125* @param loader a classloader to use126*/127public void setClassLoader(ClassLoader loader) {128this.loader = new WeakReference<ClassLoader>(loader);129}130131/**132* Returns the exception listener for parsing.133* The exception listener is notified134* when handler catches recoverable exceptions.135* If the exception listener has not been explicitly set136* then default exception listener is returned.137*138* @return the exception listener for parsing139*/140public ExceptionListener getExceptionListener() {141return this.listener;142}143144/**145* Sets the exception listener for parsing.146* The exception listener is notified147* when handler catches recoverable exceptions.148*149* @param listener the exception listener for parsing150*/151public void setExceptionListener(ExceptionListener listener) {152this.listener = listener;153}154155/**156* Returns the owner of this document handler.157*158* @return the owner of this document handler159*/160public Object getOwner() {161return this.owner;162}163164/**165* Sets the owner of this document handler.166*167* @param owner the owner of this document handler168*/169public void setOwner(Object owner) {170this.owner = owner;171}172173/**174* Returns the handler for the element with specified name.175*176* @param name the name of the element177* @return the corresponding element handler178*/179public Class<? extends ElementHandler> getElementHandler(String name) {180Class<? extends ElementHandler> type = this.handlers.get(name);181if (type == null) {182throw new IllegalArgumentException("Unsupported element: " + name);183}184return type;185}186187/**188* Sets the handler for the element with specified name.189*190* @param name the name of the element191* @param handler the corresponding element handler192*/193public void setElementHandler(String name, Class<? extends ElementHandler> handler) {194this.handlers.put(name, handler);195}196197/**198* Indicates whether the variable with specified identifier is defined.199*200* @param id the identifier201* @return @{code true} if the variable is defined;202* @{code false} otherwise203*/204public boolean hasVariable(String id) {205return this.environment.containsKey(id);206}207208/**209* Returns the value of the variable with specified identifier.210*211* @param id the identifier212* @return the value of the variable213*/214public Object getVariable(String id) {215if (!this.environment.containsKey(id)) {216throw new IllegalArgumentException("Unbound variable: " + id);217}218return this.environment.get(id);219}220221/**222* Sets new value of the variable with specified identifier.223*224* @param id the identifier225* @param value new value of the variable226*/227public void setVariable(String id, Object value) {228this.environment.put(id, value);229}230231/**232* Returns the array of readed objects.233*234* @return the array of readed objects235*/236public Object[] getObjects() {237return this.objects.toArray();238}239240/**241* Adds the object to the list of readed objects.242*243* @param object the object that is readed from XML document244*/245void addObject(Object object) {246this.objects.add(object);247}248249/**250* Disables any external entities.251*/252@Override253public InputSource resolveEntity(String publicId, String systemId) {254return new InputSource(new StringReader(""));255}256257/**258* Prepares this handler to read objects from XML document.259*/260@Override261public void startDocument() {262this.objects.clear();263this.handler = null;264}265266/**267* Parses opening tag of XML element268* using corresponding element handler.269*270* @param uri the namespace URI, or the empty string271* if the element has no namespace URI or272* if namespace processing is not being performed273* @param localName the local name (without prefix), or the empty string274* if namespace processing is not being performed275* @param qName the qualified name (with prefix), or the empty string276* if qualified names are not available277* @param attributes the attributes attached to the element278*/279@Override280@SuppressWarnings("deprecation")281public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {282ElementHandler parent = this.handler;283try {284this.handler =285getElementHandler(qName).newInstance();286this.handler.setOwner(this);287this.handler.setParent(parent);288}289catch (Exception exception) {290throw new SAXException(exception);291}292for (int i = 0; i < attributes.getLength(); i++)293try {294String name = attributes.getQName(i);295String value = attributes.getValue(i);296this.handler.addAttribute(name, value);297}298catch (RuntimeException exception) {299handleException(exception);300}301302this.handler.startElement();303}304305/**306* Parses closing tag of XML element307* using corresponding element handler.308*309* @param uri the namespace URI, or the empty string310* if the element has no namespace URI or311* if namespace processing is not being performed312* @param localName the local name (without prefix), or the empty string313* if namespace processing is not being performed314* @param qName the qualified name (with prefix), or the empty string315* if qualified names are not available316*/317@Override318public void endElement(String uri, String localName, String qName) {319try {320this.handler.endElement();321}322catch (RuntimeException exception) {323handleException(exception);324}325finally {326this.handler = this.handler.getParent();327}328}329330/**331* Parses character data inside XML element.332*333* @param chars the array of characters334* @param start the start position in the character array335* @param length the number of characters to use336*/337@Override338public void characters(char[] chars, int start, int length) {339if (this.handler != null) {340try {341while (0 < length--) {342this.handler.addCharacter(chars[start++]);343}344}345catch (RuntimeException exception) {346handleException(exception);347}348}349}350351/**352* Handles an exception using current exception listener.353*354* @param exception an exception to handle355* @see #setExceptionListener356*/357public void handleException(Exception exception) {358if (this.listener == null) {359throw new IllegalStateException(exception);360}361this.listener.exceptionThrown(exception);362}363364/**365* Starts parsing of the specified input source.366*367* @param input the input source to parse368*/369@SuppressWarnings("removal")370public void parse(final InputSource input) {371if ((this.acc == null) && (null != System.getSecurityManager())) {372throw new SecurityException("AccessControlContext is not set");373}374AccessControlContext stack = AccessController.getContext();375SharedSecrets.getJavaSecurityAccess().doIntersectionPrivilege(new PrivilegedAction<Void>() {376public Void run() {377try {378SAXParserFactory.newInstance().newSAXParser().parse(input, DocumentHandler.this);379}380catch (ParserConfigurationException exception) {381handleException(exception);382}383catch (SAXException wrapper) {384Exception exception = wrapper.getException();385if (exception == null) {386exception = wrapper;387}388handleException(exception);389}390catch (IOException exception) {391handleException(exception);392}393return null;394}395}, stack, this.acc);396}397398/**399* Resolves class by name using current class loader.400* This method handles exception using current exception listener.401*402* @param name the name of the class403* @return the object that represents the class404*/405public Class<?> findClass(String name) {406try {407return ClassFinder.resolveClass(name, getClassLoader());408}409catch (ClassNotFoundException exception) {410handleException(exception);411return null;412}413}414}415416417