| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.catalina.storeconfig; |
| |
| import java.beans.IndexedPropertyDescriptor; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.io.PrintWriter; |
| import java.util.Iterator; |
| |
| import org.apache.tomcat.util.IntrospectionUtils; |
| import org.apache.tomcat.util.descriptor.web.ResourceBase; |
| |
| /** |
| * StoreAppends generate really the xml tag elements |
| */ |
| public class StoreAppender { |
| |
| /** |
| * The set of classes that represent persistable properties. |
| */ |
| private static Class<?> persistables[] = { String.class, Integer.class, |
| Integer.TYPE, Boolean.class, Boolean.TYPE, Byte.class, Byte.TYPE, |
| Character.class, Character.TYPE, Double.class, Double.TYPE, |
| Float.class, Float.TYPE, Long.class, Long.TYPE, Short.class, |
| Short.TYPE, }; |
| |
| /** |
| * print the closing tag |
| * |
| * @param aWriter |
| * @param aDesc |
| * @throws Exception |
| */ |
| public void printCloseTag(PrintWriter aWriter, StoreDescription aDesc) |
| throws Exception { |
| aWriter.print("</"); |
| aWriter.print(aDesc.getTag()); |
| aWriter.println(">"); |
| } |
| |
| /** |
| * print only the open tag with all attributes |
| * |
| * @param aWriter |
| * @param indent |
| * @param bean |
| * @param aDesc |
| * @throws Exception |
| */ |
| public void printOpenTag(PrintWriter aWriter, int indent, Object bean, |
| StoreDescription aDesc) throws Exception { |
| aWriter.print("<"); |
| aWriter.print(aDesc.getTag()); |
| if (aDesc.isAttributes() && bean != null) |
| printAttributes(aWriter, indent, bean, aDesc); |
| aWriter.println(">"); |
| } |
| |
| /** |
| * Print tag with all attributes |
| * |
| * @param aWriter |
| * @param indent |
| * @param bean |
| * @param aDesc |
| * @throws Exception |
| */ |
| public void printTag(PrintWriter aWriter, int indent, Object bean, |
| StoreDescription aDesc) throws Exception { |
| aWriter.print("<"); |
| aWriter.print(aDesc.getTag()); |
| if (aDesc.isAttributes() && bean != null) |
| printAttributes(aWriter, indent, bean, aDesc); |
| aWriter.println("/>"); |
| } |
| |
| /** |
| * print the value from tag as content |
| * |
| * @param aWriter |
| * @param tag |
| * @param content |
| * @throws Exception |
| */ |
| public void printTagContent(PrintWriter aWriter, String tag, String content) |
| throws Exception { |
| aWriter.print("<"); |
| aWriter.print(tag); |
| aWriter.print(">"); |
| aWriter.print(convertStr(content)); |
| aWriter.print("</"); |
| aWriter.print(tag); |
| aWriter.println(">"); |
| } |
| |
| /** |
| * print an array of values |
| * |
| * @param aWriter |
| * @param tag |
| * @param indent |
| * @param elements |
| */ |
| public void printTagValueArray(PrintWriter aWriter, String tag, int indent, |
| String[] elements) { |
| if (elements != null && elements.length > 0) { |
| printIndent(aWriter, indent + 2); |
| aWriter.print("<"); |
| aWriter.print(tag); |
| aWriter.print(">"); |
| for (int i = 0; i < elements.length; i++) { |
| printIndent(aWriter, indent + 4); |
| aWriter.print(elements[i]); |
| if (i + 1 < elements.length) |
| aWriter.println(","); |
| } |
| printIndent(aWriter, indent + 2); |
| aWriter.print("</"); |
| aWriter.print(tag); |
| aWriter.println(">"); |
| } |
| } |
| |
| /** |
| * print a array of elements |
| * |
| * @param aWriter |
| * @param tag |
| * @param indent |
| * @param elements |
| */ |
| public void printTagArray(PrintWriter aWriter, String tag, int indent, |
| String[] elements) throws Exception { |
| if (elements != null) { |
| for (int i = 0; i < elements.length; i++) { |
| printIndent(aWriter, indent); |
| printTagContent(aWriter, tag, elements[i]); |
| } |
| } |
| } |
| |
| /** |
| * Print some spaces |
| * |
| * @param aWriter |
| * @param indent |
| * number of spaces |
| */ |
| public void printIndent(PrintWriter aWriter, int indent) { |
| for (int i = 0; i < indent; i++) { |
| aWriter.print(' '); |
| } |
| } |
| |
| /** |
| * Store the relevant attributes of the specified JavaBean, plus a |
| * <code>className</code> attribute defining the fully qualified Java |
| * class name of the bean. |
| * |
| * @param writer |
| * PrintWriter to which we are storing |
| * @param bean |
| * Bean whose properties are to be rendered as attributes, |
| * |
| * @exception Exception |
| * if an exception occurs while storing |
| */ |
| public void printAttributes(PrintWriter writer, int indent, Object bean, |
| StoreDescription desc) throws Exception { |
| |
| printAttributes(writer, indent, true, bean, desc); |
| |
| } |
| |
| /** |
| * Store the relevant attributes of the specified JavaBean. |
| * |
| * @param writer |
| * PrintWriter to which we are storing |
| * @param include |
| * Should we include a <code>className</code> attribute? |
| * @param bean |
| * Bean whose properties are to be rendered as attributes, |
| * @param desc |
| * RegistryDescrpitor from this bean |
| * |
| * @exception Exception |
| * if an exception occurs while storing |
| */ |
| public void printAttributes(PrintWriter writer, int indent, |
| boolean include, Object bean, StoreDescription desc) |
| throws Exception { |
| |
| // Render a className attribute if requested |
| if (include && desc != null && !desc.isStandard()) { |
| writer.print(" className=\""); |
| writer.print(bean.getClass().getName()); |
| writer.print("\""); |
| } |
| |
| // Acquire the list of properties for this bean |
| PropertyDescriptor descriptors[] = Introspector.getBeanInfo( |
| bean.getClass()).getPropertyDescriptors(); |
| if (descriptors == null) { |
| descriptors = new PropertyDescriptor[0]; |
| } |
| |
| // Create blank instance |
| Object bean2 = defaultInstance(bean); |
| for (int i = 0; i < descriptors.length; i++) { |
| if (descriptors[i] instanceof IndexedPropertyDescriptor) { |
| continue; // Indexed properties are not persisted |
| } |
| if (!isPersistable(descriptors[i].getPropertyType()) |
| || (descriptors[i].getReadMethod() == null) |
| || (descriptors[i].getWriteMethod() == null)) { |
| continue; // Must be a read-write primitive or String |
| } |
| if (desc.isTransientAttribute(descriptors[i].getName())) { |
| continue; // Skip the specified exceptions |
| } |
| Object value = IntrospectionUtils.getProperty(bean, descriptors[i] |
| .getName()); |
| if (value == null) { |
| continue; // Null values are not persisted |
| } |
| Object value2 = IntrospectionUtils.getProperty(bean2, |
| descriptors[i].getName()); |
| if (value.equals(value2)) { |
| // The property has its default value |
| continue; |
| } |
| printAttribute(writer, indent, bean, desc, descriptors[i].getName(), bean2, value); |
| } |
| |
| if (bean instanceof ResourceBase) { |
| ResourceBase resource = (ResourceBase) bean; |
| for (Iterator<String> iter = resource.listProperties(); iter.hasNext();) { |
| String name = iter.next(); |
| Object value = resource.getProperty(name); |
| if (!isPersistable(value.getClass())) { |
| continue; |
| } |
| if (desc.isTransientAttribute(name)) { |
| continue; // Skip the specified exceptions |
| } |
| printValue(writer, indent, name, value); |
| |
| } |
| } |
| } |
| |
| /** |
| * @param writer |
| * @param indent |
| * @param bean |
| * @param desc |
| * @param attributeName |
| * @param bean2 |
| * @param value |
| */ |
| protected void printAttribute(PrintWriter writer, int indent, Object bean, StoreDescription desc, String attributeName, Object bean2, Object value) { |
| if (isPrintValue(bean, bean2, attributeName, desc)) |
| printValue(writer, indent, attributeName, value); |
| } |
| |
| /** |
| * print this Attribute value or not |
| * |
| * @param bean |
| * orginal bean |
| * @param bean2 |
| * default bean |
| * @param attrName |
| * attribute name |
| * @param desc |
| * StoreDescription from bean |
| * @return True if it's a printing value |
| */ |
| public boolean isPrintValue(Object bean, Object bean2, String attrName, |
| StoreDescription desc) { |
| boolean printValue = false; |
| |
| Object value = IntrospectionUtils.getProperty(bean, attrName); |
| if (value != null) { |
| Object value2 = IntrospectionUtils.getProperty(bean2, attrName); |
| printValue = !value.equals(value2); |
| |
| } |
| return printValue; |
| } |
| |
| /** |
| * generate default Instance |
| * |
| * @param bean |
| * @return an object from same class as bean parameter |
| * @throws InstantiationException |
| * @throws IllegalAccessException |
| */ |
| public Object defaultInstance(Object bean) throws InstantiationException, |
| IllegalAccessException { |
| return bean.getClass().newInstance(); |
| } |
| |
| /** |
| * print an attribute value |
| * |
| * @param writer |
| * @param name |
| * @param value |
| */ |
| public void printValue(PrintWriter writer, int indent, String name, |
| Object value) { |
| if (!(value instanceof String)) { |
| value = value.toString(); |
| } |
| writer.println(); |
| printIndent(writer, indent + 4); |
| writer.print(name); |
| writer.print("=\""); |
| String strValue = convertStr((String) value); |
| writer.print(strValue); |
| writer.print("\""); |
| } |
| |
| /** |
| * Given a string, this method replaces all occurrences of ' <', '>', '&', |
| * and '"'. |
| */ |
| public String convertStr(String input) { |
| |
| StringBuffer filtered = new StringBuffer(input.length()); |
| char c; |
| for (int i = 0; i < input.length(); i++) { |
| c = input.charAt(i); |
| if (c == '<') { |
| filtered.append("<"); |
| } else if (c == '>') { |
| filtered.append(">"); |
| } else if (c == '\'') { |
| filtered.append("'"); |
| } else if (c == '"') { |
| filtered.append("""); |
| } else if (c == '&') { |
| filtered.append("&"); |
| } else { |
| filtered.append(c); |
| } |
| } |
| return (filtered.toString()); |
| } |
| |
| /** |
| * Is the specified property type one for which we should generate a |
| * persistence attribute? |
| * |
| * @param clazz |
| * Java class to be tested |
| */ |
| protected boolean isPersistable(Class<?> clazz) { |
| |
| for (int i = 0; i < persistables.length; i++) { |
| if (persistables[i] == clazz) { |
| return (true); |
| } |
| } |
| return (false); |
| |
| } |
| } |