001    /*
002    @license.text@
003     */
004    
005    package biz.hammurapi.render.dom;
006    
007    import java.io.IOException;
008    import java.io.InputStream;
009    import java.io.OutputStream;
010    import java.io.UnsupportedEncodingException;
011    import java.util.HashMap;
012    import java.util.Iterator;
013    import java.util.Map;
014    
015    import javax.xml.parsers.DocumentBuilder;
016    import javax.xml.parsers.DocumentBuilderFactory;
017    import javax.xml.parsers.ParserConfigurationException;
018    import javax.xml.transform.Templates;
019    import javax.xml.transform.Transformer;
020    import javax.xml.transform.TransformerConfigurationException;
021    import javax.xml.transform.TransformerException;
022    import javax.xml.transform.TransformerFactory;
023    import javax.xml.transform.dom.DOMSource;
024    import javax.xml.transform.stream.StreamResult;
025    import javax.xml.transform.stream.StreamSource;
026    
027    import org.w3c.dom.Element;
028    
029    import biz.hammurapi.config.Parameterizable;
030    import biz.hammurapi.render.RenderRequest;
031    import biz.hammurapi.render.RenderingException;
032    
033    
034    /**
035     *
036     * @author  Pavel Vlasov
037     * @version $Revision: 1.5 $
038     */
039    public abstract class AbstractRenderer implements DomRenderer, Parameterizable {
040        private static class StyleKey {
041            Class clazz;
042            String profile;
043            
044            public StyleKey(Class clazz, String profile) {
045                super();
046                this.clazz = clazz;
047                this.profile = profile;
048            }
049            
050            public boolean equals(Object obj) {
051                if (obj==this) {
052                    return true;
053                } else if (obj instanceof StyleKey) {
054                    StyleKey otherKey=(StyleKey) obj;
055                    if (clazz.equals(otherKey.clazz)) {
056                        if (profile==null) {
057                            return otherKey.profile==null;
058                        } else if (otherKey.profile==null) {
059                            return false;
060                        } else {
061                            return profile.equals(otherKey.profile);
062                        }
063                    }
064                                    return false;
065                } else {
066                    return super.equals(obj);
067                }
068            }
069            
070            public int hashCode() {
071                int ret=clazz.hashCode();
072                if (profile!=null) {
073                    ret^=profile.hashCode();
074                }
075                return ret;
076            }
077        }
078        
079        private static Map styleMap=new HashMap();
080        
081        protected RenderRequest request;
082        protected String profile;
083        public static final String PROFILE_SEPARATOR="!";
084           
085        protected AbstractRenderer(RenderRequest request) {
086            this.request=request;
087        }
088        
089        protected AbstractRenderer(RenderRequest request, String profile) {
090            this.request=request;
091            this.profile=profile;
092        }
093        
094        /**
095         * Searches for class name first, then for all interfaces and then for 
096         * superclass.
097         * @param clazz
098         * @return
099         * @throws TransformerConfigurationException
100         */
101        public synchronized Transformer getEmbeddedStyle(Class clazz) throws TransformerConfigurationException {
102            StyleKey key=new StyleKey(clazz, profile);
103            Templates templates=(Templates) styleMap.get(key);
104            if (templates==null) {
105                String transletClass=clazz.getName()+StyleCompiler.POSTFIX;
106                if (profile!=null) {
107                    transletClass+=StyleCompiler.TRANSLET_PROFILE_SEPARATOR+profile;
108                }
109                
110    //            try {
111    //                getClass().getClassLoader().loadClass(transletClass);
112    //                int idx=transletClass.lastIndexOf('.');
113    //                      TransformerFactory tf=new TransformerFactoryImpl();
114    //                tf.setAttribute("use-classpath", Boolean.TRUE);
115    //                if (idx!=-1) {
116    //                      tf.setAttribute("package-name", transletClass.substring(0, idx));
117    //                }
118    //                      templates=tf.newTemplates(new StreamSource(idx==-1 ? transletClass : transletClass.substring(idx+1)));
119    //                      styleMap.put(key, templates);
120    //                      return templates.newTransformer();
121    //            } catch (ClassNotFoundException e) {
122                        String resourceName=clazz.getName().replace('.','/')+(profile==null ? "" : PROFILE_SEPARATOR+profile)+".xsl";
123                        InputStream rets=getClass().getClassLoader().getResourceAsStream(resourceName);
124                        if (rets!=null) {
125                            TransformerFactory tf=TransformerFactory.newInstance();
126                            templates=tf.newTemplates(new StreamSource(rets));
127                            styleMap.put(key, templates);
128                            return templates.newTransformer();
129                        }
130    //            }
131                
132                Class[] interfaces = clazz.getInterfaces();
133                    for (int i=0; i<interfaces.length; i++) {
134                            Transformer rett=getEmbeddedStyle(interfaces[i]);
135                            if (rett!=null) {
136                                    return rett;
137                            }
138                }
139                    
140                    if (clazz.getSuperclass()==null) {
141                        styleMap.put(key, null);
142                        return null;
143                    }
144                            return getEmbeddedStyle(clazz.getSuperclass());
145            }
146                    return templates.newTransformer();
147        }    
148        
149        public RenderRequest render(OutputStream out) throws RenderingException {
150            return render(null, out);
151        }
152        
153        public RenderRequest render(InputStream style, OutputStream out) throws RenderingException {
154            try {
155                Transformer transformer=null;
156    
157                if (style==null && useEmbeddedStyle) {
158                    transformer=getEmbeddedStyle(request.getRenderee().getClass());
159                } 
160                
161                if (transformer==null) {
162                    TransformerFactory tFactory = TransformerFactory.newInstance();                
163                    transformer =
164                        style==null ?
165                            tFactory.newTransformer() :
166                            tFactory.newTransformer(new StreamSource(style));
167                }
168    
169                Iterator pit=params.entrySet().iterator();
170                while (pit.hasNext()) {
171                    Map.Entry entry=(Map.Entry) pit.next();
172                    transformer.setParameter((String) entry.getKey(), entry.getValue());
173                }
174    
175                DocumentBuilder builder=null;
176                
177                if (request.getDocument()==null) {
178                        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
179                        builder=factory.newDocumentBuilder();
180                        request.setDocument(builder.newDocument());
181                        request.getDocument().appendChild(render(request.getDocument()));
182                }
183                
184                DOMSource domSource = new DOMSource(request.getDocument());
185                transformer.transform(domSource, new StreamResult(out));
186                out.close();
187                return request;
188            } catch (TransformerConfigurationException e) {
189                throw new RenderingException(e.toString(), e);
190            } catch (ParserConfigurationException e) {
191                throw new RenderingException(e.toString(), e);
192            } catch (TransformerException e) {
193                throw new RenderingException(e.toString(), e);
194            } catch (UnsupportedEncodingException e) {
195                throw new RenderingException(e.toString(), e);
196            } catch (IOException e) {
197                throw new RenderingException(e.toString(), e);
198            }            
199        }
200    
201        protected boolean useEmbeddedStyle=true;
202        
203        public void setEmbeddedStyle(boolean useEmbeddedStyle) {
204            this.useEmbeddedStyle=useEmbeddedStyle;
205        }
206            
207        protected Map params=new HashMap();
208        
209        public boolean setParameter(String name, Object value) {
210            params.put(name, value);
211            return true;
212        }
213    
214            /**
215             * Creates and add element with text if text!=null && name!=null
216             * @param name
217             * @param text
218             * @param owner
219             * @return
220             */
221            public static void appendTextElement(String name, String text, Element owner) {
222                    if (name!=null && text!=null) {
223                            Element e=owner.getOwnerDocument().createElement(name);
224                            owner.appendChild(e);
225                            e.appendChild(owner.getOwnerDocument().createTextNode(text));
226                    }
227            }
228    }