001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.jms.adapter.converters; 005 006 import java.io.IOException; 007 import java.io.StringReader; 008 import java.io.StringWriter; 009 import java.net.MalformedURLException; 010 import java.net.URL; 011 import java.util.HashMap; 012 import java.util.Map; 013 014 import javax.jms.Message; 015 import javax.jms.Session; 016 import javax.jms.TextMessage; 017 import javax.xml.parsers.DocumentBuilder; 018 import javax.xml.parsers.DocumentBuilderFactory; 019 import javax.xml.transform.Result; 020 import javax.xml.transform.Source; 021 import javax.xml.transform.Templates; 022 import javax.xml.transform.Transformer; 023 import javax.xml.transform.TransformerConfigurationException; 024 import javax.xml.transform.TransformerFactory; 025 import javax.xml.transform.dom.DOMSource; 026 import javax.xml.transform.stream.StreamResult; 027 import javax.xml.transform.stream.StreamSource; 028 029 import org.w3c.dom.Document; 030 import org.w3c.dom.Element; 031 032 import biz.hammurapi.config.ComponentBase; 033 import biz.hammurapi.config.ConfigurationException; 034 import biz.hammurapi.jms.adapter.Converter; 035 import biz.hammurapi.jms.adapter.JmsAdapter; 036 import biz.hammurapi.xml.dom.DOMUtils; 037 038 /** 039 * This converter supports the following optional conversion properties: 040 * <UL> 041 * <LI>from-xml-style - URL of stylesheet to apply before XML -> Object conversion. 042 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 043 * <LI>to-xml-style - URL of stylesheet to apply after Object -> XML conversion. 044 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 045 * <LI>error-style - URL of stylesheet to apply after Exception -> XML conversion. 046 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 047 * </UL> 048 * @author Tatyana Konukova 049 * 050 */ 051 public abstract class StylingXmlConverter extends ComponentBase implements Converter { 052 053 private static final String RESOURCE_PREFIX = "resource:"; 054 private Map templates = new HashMap(); 055 056 private DocumentBuilder documentBuilder; 057 058 protected synchronized Document createDocument() { 059 return documentBuilder.newDocument(); 060 } 061 062 /** 063 * Creates result to receive transformed input. 064 * @return Result instance. 065 */ 066 protected abstract Result createResult(); 067 068 /** 069 * Converts reply result to object. 070 * @param result 071 * @return 072 */ 073 protected abstract Object processResult(Result result) throws Exception; 074 // return ((StringWriter) ((StreamResult) result).getWriter()).toString(); 075 076 /** 077 * Converts request object to Source for styling/serialization 078 * @param request 079 * @return 080 */ 081 protected abstract Source convert(Object request) throws Exception; 082 083 protected TransformerFactory transformerFactory; 084 085 public void start() throws ConfigurationException { 086 try { 087 documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 088 transformerFactory = TransformerFactory.newInstance(); 089 } catch (Exception e) { 090 throw new ConfigurationException("Startup failed: "+e, e); 091 } 092 } 093 094 protected Transformer getTransformer(String url) throws TransformerConfigurationException, MalformedURLException, IOException { 095 if (JmsAdapter.isBlank(url)) { 096 return null; 097 } 098 099 synchronized (templates) { 100 Templates template = (Templates) templates.get(url); 101 if (template==null) { 102 if (url.startsWith(RESOURCE_PREFIX)) { 103 template = transformerFactory.newTemplates( 104 new StreamSource( 105 getClass() 106 .getClassLoader() 107 .getResourceAsStream( 108 url.substring(RESOURCE_PREFIX.length())))); 109 } else { 110 template = transformerFactory.newTemplates(new StreamSource(new URL(url).openStream())); 111 } 112 templates.put(url, template); 113 } 114 return template.newTransformer(); 115 } 116 } 117 118 /** 119 * This method supports <code>from-xml-style</code> optional property - URL of stylesheet to apply before XML -> Object conversion. 120 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 121 */ 122 public Object convert(Message message, Map properties) throws Exception { 123 Result result = createResult(); 124 Transformer transformer = getTransformer((String) properties.get("from-xml-style")); 125 if (transformer==null) { 126 transformer = transformerFactory.newTransformer(); 127 } 128 transformer.transform(new StreamSource(new StringReader(((TextMessage) message).getText())), result); 129 return processResult(result); 130 } 131 132 /** 133 * This method supports <code>to-xml-style</code> optional property - URL of stylesheet to apply after Object -> XML conversion. 134 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 135 * Correlates by message ID. 136 */ 137 public Message convert(Object obj, Session session, Map properties, Message request) throws Exception { 138 TextMessage ret = session.createTextMessage(); 139 Transformer transformer = getTransformer((String) properties.get("to-xml-style")); 140 if (transformer==null) { 141 transformer = transformerFactory.newTransformer(); 142 } 143 StringWriter sw = new StringWriter(); 144 transformer.transform(convert(obj), new StreamResult(sw)); 145 sw.close(); 146 ret.setText(sw.toString()); 147 if (request!=null) { 148 ret.setJMSCorrelationID(request.getJMSMessageID()); 149 } 150 return ret; 151 } 152 153 /** 154 * This method supports <code>error-style</code> optional property - URL of stylesheet to apply after Exception -> Conversion. 155 * If URL starts with <code>resource:</code> then it is loaded from classloader resource.</LI> 156 * This implementation uses ThrowableSerializer to convert exception to XML. 157 * Correlates by message ID. 158 */ 159 public Message convert(Exception ex, Session session, Map properties, Message request) throws Exception { 160 TextMessage ret = session.createTextMessage(); 161 Document doc = createDocument(); 162 Element root = doc.createElement("error"); 163 doc.appendChild(root); 164 DOMUtils.toDom(ex, root); 165 166 StringWriter sw = new StringWriter(); 167 Transformer transformer = getTransformer((String) properties.get("error-style")); 168 if (transformer==null) { 169 DOMUtils.serialize(doc, sw); 170 // XMLSerializer xmlSerializer = new XMLSerializer(sw, new OutputFormat("xml","UTF-8",false)); 171 // xmlSerializer.setNamespaces(true); 172 // xmlSerializer.serialize(doc); 173 } else { 174 transformer.transform(new DOMSource(doc), new StreamResult(sw)); 175 } 176 sw.close(); 177 ret.setText(sw.toString()); 178 if (request!=null) { 179 ret.setJMSCorrelationID(request.getJMSMessageID()); 180 } 181 return ret; 182 } 183 184 public void stop() throws ConfigurationException { 185 // Nothing to do 186 } 187 188 }