/*
* Copyright 2007 Luigi Dell'Aquila (luigi.dellaquila@assetdata.it)
*
* Licensed 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.reverspring.xml;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.reverspring.engine.BeanDescriptor;
import org.reverspring.engine.BeanSet;
import org.reverspring.engine.DescriptorGenerator;
import org.reverspring.engine.ObjectBinding;
/**
* This class provides mehods to generate Spring IoC XML descriptors from {@link BeanSet} objects.
*
* @see BeanSet
* @see DescriptorGenerator
*
* @author Luigi Dell'Aquila
*
*/
public class XmlGenerator {
private static char[] ODD_CHARS = new char[] { '&', '<', '>' };
/**
* generates an xml document from a bean set
*
* @param beanSet
* the bean set containing the description of the beans to be written in the descriptor
* @return a Spring xml descriptor
*/
public static String getXml(BeanSet beanSet) {
StringBuffer buffer = new StringBuffer();
buffer.append("<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" ");
buffer.append("\"http://www.springframework.org/dtd/spring-beans.dtd\">\n");
buffer.append("<beans default-lazy-init=\"true\" default-autowire=\"no\">\n");
Set<String> beansProcessed = new HashSet<String>();
for (BeanDescriptor descriptor : beanSet.getBeans()) {
if (descriptor.getType() != BeanDescriptor.TYPE_LIST && descriptor.getType() != BeanDescriptor.TYPE_SET
&& descriptor.getType() != BeanDescriptor.TYPE_MAP) {
if (!beansProcessed.contains(descriptor.getId()))
writeBean(descriptor, buffer, beansProcessed, 1);
}
}
buffer.append("</beans>");
return buffer.toString();
}
/**
* generates an XML document from a bean set and saves it on a file
*
* @param beanSet
* the bean set containing the description of the beans to be written in the descriptor
* @param file
* the file where to save the xml
* @throws IOException
*/
public static void save(BeanSet beanSet, File file) throws IOException {
FileWriter writer = new FileWriter(file);
writer.write(XmlGenerator.getXml(beanSet));
writer.flush();
writer.close();
}
private static void pad(int steps, StringBuffer buffer) {
for (int i = 0; i < steps; i++) {
buffer.append(" ");
}
}
private static void writeBean(BeanDescriptor descriptor, StringBuffer buffer, Set<String> beansProcessed, int indent) {
pad(indent, buffer);
buffer.append("<bean ");
buffer.append("class=\"" + descriptor.getBean().getClass().getName() + "\" ");
buffer.append("id=\"" + descriptor.getId() + "\">\n");
beansProcessed.add(descriptor.getId());
// constructor
if (descriptor.getConstructorArguments() != null && descriptor.getConstructorArguments().length > 0) {
for (ObjectBinding binding : descriptor.getConstructorArguments()) {
XmlGenerator.writeConstructorArg(binding, buffer, beansProcessed, indent + 1);
}
}
for (String propertyName : descriptor.getProperties()) {
if (descriptor.getBinding(propertyName) != null
&& descriptor.getBinding(propertyName).getDescriptor().getType() == BeanDescriptor.TYPE_BASE) {
boolean inline = descriptor.getBinding(propertyName).isNested();
XmlGenerator.writeSimpleProperty(propertyName, descriptor.getBinding(propertyName).getDescriptor().getBean().toString(),
inline, buffer, indent + 1);
} else if (descriptor.getBinding(propertyName) != null) {
XmlGenerator.writeRefProperty(propertyName, descriptor.getBinding(propertyName), beansProcessed, buffer, indent + 1);
} else if (descriptor.getListProperty(propertyName) != null) {// list of objects
XmlGenerator.writeListProperty(propertyName, descriptor.getListProperty(propertyName), beansProcessed, buffer, indent + 1);
} else if (descriptor.getSetProperty(propertyName) != null) {// set of objects
XmlGenerator.writeSetProperty(propertyName, descriptor.getSetProperty(propertyName), beansProcessed, buffer, indent + 1);
} else if (descriptor.getMapProperty(propertyName) != null) {
XmlGenerator.writeMapProperty(propertyName, descriptor.getMapProperty(propertyName), beansProcessed, buffer, indent + 1);
} else { // null value
XmlGenerator.writeSimpleProperty(propertyName, null, false, buffer, indent + 1);
}
}
pad(indent, buffer);
buffer.append("</bean>\n");
}
private static void writeConstructorArg(ObjectBinding argument, StringBuffer buffer, Set<String> beansProcessed, int indent) {
pad(indent, buffer);
buffer.append("<constructor-arg>\n");
if (argument.getDescriptor().getBean() == null) {
buffer.append("<null/>\n");
} else if (argument.getDescriptor().getType() == BeanDescriptor.TYPE_BASE) {
writeSimplePropertyValue(argument, buffer, indent + 1);
} else {
writeRef(argument.getDescriptor().getId(), buffer, indent + 1);
}
pad(indent, buffer);
buffer.append("</constructor-arg>\n");
}
private static void writeSetProperty(String propertyName, Set<ObjectBinding> value, Set<String> beansProcessed,
StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<property name=\"" + propertyName + "\">\n");
writeSetContent(value, beansProcessed, buffer, indent + 1);
pad(indent, buffer);
buffer.append("</property>\n");
}
private static void writeSetContent(Set<ObjectBinding> value, Set<String> beansProcessed, StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<set>\n");
if (value != null) {
for (ObjectBinding ref : value) {
BeanDescriptor descriptor = ref.getDescriptor();
if (descriptor.getType() == BeanDescriptor.TYPE_BASE) {
writeSimplePropertyValue(ref, buffer, indent + 1);
} else {
if (ref.isNested() && !beansProcessed.contains(ref.getDescriptor().getId())) {
writeBean(descriptor, buffer, beansProcessed, indent + 1);
} else {
writeRef(descriptor.getId(), buffer, indent + 1);
}
}
}
}
pad(indent, buffer);
buffer.append("</set>\n");
}
private static void writeListProperty(String propertyName, List<ObjectBinding> value, Set<String> beansProcessed,
StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<property name=\"" + propertyName + "\">\n");
writeListContent(value, beansProcessed, buffer, indent + 1);
pad(indent, buffer);
buffer.append("</property>\n");
}
private static void writeListContent(List<ObjectBinding> value, Set<String> beansProcessed, StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<list>\n");
if (value != null) {
for (ObjectBinding ref : value) {
BeanDescriptor descriptor = ref.getDescriptor();
if (descriptor.getType() == BeanDescriptor.TYPE_BASE) {
writeSimplePropertyValue(ref, buffer, indent + 1);
} else if (ref.getDescriptor().getType() == BeanDescriptor.TYPE_LIST) {
writeListContent(ref.getDescriptor().getListProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer, indent + 1);
} else if (ref.getDescriptor().getType() == BeanDescriptor.TYPE_SET) {
writeSetContent(ref.getDescriptor().getSetProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer, indent + 1);
} else if (ref.getDescriptor().getType() == BeanDescriptor.TYPE_MAP) {
writeMapContent(ref.getDescriptor().getMapProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer, indent + 1);
} else {
if (ref.isNested() && !beansProcessed.contains(ref.getDescriptor().getId())) {
writeBean(descriptor, buffer, beansProcessed, indent + 1);
} else {
writeRef(descriptor.getId(), buffer, indent + 1);
}
}
}
}
pad(indent, buffer);
buffer.append("</list>\n");
}
private static void writeMapProperty(String propertyName, Map<ObjectBinding, ObjectBinding> value, Set<String> beansProcessed,
StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<property name=\"" + propertyName + "\">\n");
writeMapContent(value, beansProcessed, buffer, indent + 1);
pad(indent, buffer);
buffer.append("</property>\n");
}
private static void writeMapContent(Map<ObjectBinding, ObjectBinding> value, Set<String> beansProcessed, StringBuffer buffer,
int indent) {
pad(indent, buffer);
buffer.append("<map>\n");
for (ObjectBinding mapKey : value.keySet()) {
ObjectBinding mapValue = value.get(mapKey);
pad(indent + 1, buffer);
buffer.append("<entry>\n");
pad(indent + 2, buffer);
buffer.append("<key>\n");
if (mapKey.getDescriptor().getType() == BeanDescriptor.TYPE_BASE) {
writeSimplePropertyValue(mapKey, buffer, indent + 3);
} else {
if (mapKey.isNested() && !beansProcessed.contains(mapKey.getDescriptor().getId()))
writeBean(mapKey.getDescriptor(), buffer, beansProcessed, indent + 3);
else
writeRef(mapKey.getDescriptor().getId(), buffer, indent + 3);
}
pad(indent + 2, buffer);
buffer.append("</key>\n");
if (mapValue.getDescriptor().getBean() == null) {
writeNull(buffer, indent + 2);
} else if (mapValue.getDescriptor().getType() == BeanDescriptor.TYPE_BASE) {
writeSimplePropertyValue(mapValue, buffer, indent + 2);
} else if (mapValue.getDescriptor().getType() == BeanDescriptor.TYPE_LIST) {
writeListContent(mapValue.getDescriptor().getListProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer,
indent + 2);
} else if (mapValue.getDescriptor().getType() == BeanDescriptor.TYPE_SET) {
writeSetContent(mapValue.getDescriptor().getSetProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer,
indent + 2);
} else if (mapValue.getDescriptor().getType() == BeanDescriptor.TYPE_MAP) {
writeMapContent(mapValue.getDescriptor().getMapProperty(BeanDescriptor.PROPERTY_CONTENT), beansProcessed, buffer,
indent + 2);
} else {
if (mapValue.isNested() && !beansProcessed.contains(mapValue.getDescriptor().getId())) {
writeBean(mapValue.getDescriptor(), buffer, beansProcessed, indent + 2);
} else {
writeRef(mapValue.getDescriptor().getId(), buffer, indent + 2);
}
}
pad(indent + 1, buffer);
buffer.append("</entry>\n");
}
pad(indent, buffer);
buffer.append("</map>\n");
}
private static void writeSimplePropertyValue(ObjectBinding actualValue, StringBuffer buffer, int indent) {
Object bean = actualValue.getDescriptor().getBean();
if (bean == null) {
writeNull(buffer, indent);
return;
}
pad(indent, buffer);
buffer.append("<value");
if (actualValue.getDescriptor().getType() == BeanDescriptor.TYPE_BASE) {
buffer.append(" type=\"" + bean.getClass().getName() + "\"");
}
buffer.append(">");
buffer.append(bean.toString());
buffer.append("</value>\n");
}
private static void writeSimpleProperty(String name, String value, boolean inline, StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<property name=\"" + name + "\">\n");
if (value != null) {
pad(indent + 1, buffer);
buffer.append("<value>");
if (containsOddChars(value)) {
buffer.append("<![CDATA[");
buffer.append(value);
buffer.append("]]>");
} else {
buffer.append(value);
}
buffer.append("</value>\n");
} else {
writeNull(buffer, indent + 1);
}
pad(indent, buffer);
buffer.append("</property>\n");
}
private static boolean containsOddChars(String value) {
for (char c : ODD_CHARS)
if (value.indexOf(c) > -1) {
return true;
}
return false;
}
private static void writeRefProperty(String name, ObjectBinding binding, Set<String> beansProcessed, StringBuffer buffer,
int indent) {
pad(indent, buffer);
buffer.append("<property name=\"" + name + "\">\n");
writeRef(binding.getDescriptor().getId(), buffer, indent + 1);
pad(indent, buffer);
buffer.append("</property>\n");
}
private static void writeRef(String id, StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<ref bean=\"" + id + "\" />\n");
}
private static void writeNull(StringBuffer buffer, int indent) {
pad(indent, buffer);
buffer.append("<null/>\n");
}
}