EMMA Coverage Report (generated Thu Jan 20 11:39:44 EST 2011)
[all classes][com.hammurapi.render]

COVERAGE SUMMARY FOR SOURCE FILE [RenderHelper.java]

nameclass, %method, %block, %line, %
RenderHelper.java0%   (0/1)0%   (0/23)0%   (0/870)0%   (0/165)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class RenderHelper0%   (0/1)0%   (0/23)0%   (0/870)0%   (0/165)
<static initializer> 0%   (0/1)0%   (0/5)0%   (0/2)
RenderHelper (IdentityManager, File, Map, Context, Locale, boolean): void 0%   (0/1)0%   (0/26)0%   (0/9)
convert (Object, String): Object 0%   (0/1)0%   (0/21)0%   (0/4)
createObject (String, ClassLoader, Object []): Object 0%   (0/1)0%   (0/80)0%   (0/11)
escapeHtml (String): String 0%   (0/1)0%   (0/90)0%   (0/22)
getAttribute (Object, String): Object 0%   (0/1)0%   (0/24)0%   (0/5)
getAttribute (Object, String, String): Object 0%   (0/1)0%   (0/24)0%   (0/5)
getId (Object): Object 0%   (0/1)0%   (0/5)0%   (0/1)
getIdentityManager (): IdentityManager 0%   (0/1)0%   (0/3)0%   (0/1)
getImageName (Object): String 0%   (0/1)0%   (0/84)0%   (0/15)
getOutputDir (): File 0%   (0/1)0%   (0/3)0%   (0/1)
isBlank (String): boolean 0%   (0/1)0%   (0/10)0%   (0/1)
null2blank (String): String 0%   (0/1)0%   (0/6)0%   (0/1)
removeAttribute (Object, String): Object 0%   (0/1)0%   (0/24)0%   (0/5)
render (Object, String): String 0%   (0/1)0%   (0/63)0%   (0/14)
renderAndLink (Object): String 0%   (0/1)0%   (0/130)0%   (0/21)
renderDetailsAndContents (Object): void 0%   (0/1)0%   (0/89)0%   (0/13)
renderOutline (Object, Writer): void 0%   (0/1)0%   (0/6)0%   (0/2)
renderOutline (Object, Writer, boolean): void 0%   (0/1)0%   (0/25)0%   (0/4)
replaceAttribute (Object, String, Object): Object 0%   (0/1)0%   (0/38)0%   (0/8)
setAttribute (Object, String, Object): Object 0%   (0/1)0%   (0/30)0%   (0/6)
setAttributeIfAbsent (Object, String, Object): Object 0%   (0/1)0%   (0/38)0%   (0/8)
wikiLink (String): String 0%   (0/1)0%   (0/46)0%   (0/6)

1package com.hammurapi.render;
2 
3import java.io.File;
4import java.io.FileOutputStream;
5import java.io.IOException;
6import java.io.InputStream;
7import java.io.StringWriter;
8import java.io.Writer;
9import java.lang.reflect.Constructor;
10import java.util.HashMap;
11import java.util.Locale;
12import java.util.Map;
13import java.util.WeakHashMap;
14import java.util.concurrent.ConcurrentHashMap;
15 
16import com.hammurapi.common.Context;
17import com.hammurapi.common.IdentityManager;
18import com.hammurapi.common.Pumper;
19import com.hammurapi.convert.ConvertingService;
20import com.hammurapi.convert.DuckConverterFactory;
21 
22/**
23 * Helper class for ReportGenerator and Jxp renderers. 
24 * It is available in Jxp templates in ReportGenerator
25 * as <code>renderHelper</code> variable.
26 * @author Pavel Vlasov
27 *
28 */
29public class RenderHelper implements RenderingConstants {
30        
31        /**
32         * Keeps object attributes.
33         */
34        private static final Map<Object, Map<String, Object>> attributes = new WeakHashMap<Object, Map<String,Object>>();
35        
36//        private static final int BUCKETS = 200;
37        private Map<String, Object> env;
38        private Context context;
39        private Locale locale;
40        
41        private IdentityManager<?> identityManager;
42        private File outputDir;
43        private Map<Class<?>, String> classImages = new ConcurrentHashMap<Class<?>, String>();
44        private boolean http;
45        
46        /**
47         * @return Output directory.
48         */
49        public File getOutputDir() {
50                return outputDir;
51        }
52        
53        /**
54         * @return Identity manager.
55         */
56        public IdentityManager<?> getIdentityManager() {
57                return identityManager;
58        }
59        
60        /**
61         * Constructor.
62         * @param identityManager Identity manager.
63         * @param outputDir Output directory.
64         * @param env Environment.
65         * @param context Context. 
66         * @param locale Locale.
67         */
68        public RenderHelper(
69                        IdentityManager<?> identityManager, 
70                        File outputDir,
71                        Map<String, Object> env, 
72                        Context context, 
73                        Locale locale,
74                        boolean http) {
75                super();
76                this.identityManager = identityManager;
77                this.outputDir = outputDir;
78                this.env = env;
79                this.context = context;
80                this.locale = locale;
81                this.http = http;
82        }
83 
84        /**
85         * Finds image file for a given object in classloader, 
86         * writes it to the "images" directory in the 
87         * output directory, if it doesn't already exist.
88         * Image file is sought in the same way as pages - 
89         * by traversing the class hierarchy and looking for 
90         * resource with class name and .gif extension.
91         * @param obj 
92         * @return File name.
93         * @throws Exception
94         */
95        public String getImageName(Object obj) throws Exception {
96                String ret = classImages.get(obj.getClass());
97                if (ret==null) {
98                        ImageProvider imageProvider = ConvertingService.convert(obj, ImageProvider.class);
99                        if (imageProvider!=null) {
100                                File imageFile = new File(outputDir, IMAGES+File.separator+obj.getClass().getName()+"."+GIF);
101                                if (!imageFile.getParentFile().exists()) {
102                                        imageFile.getParentFile().mkdirs();
103                                }
104                                FileOutputStream imageFileOutputStream = new FileOutputStream(imageFile);
105                                InputStream imageInputStream = ConvertingService.convert(imageProvider.getIcon(), InputStream.class);
106                                if (imageInputStream!=null) {
107                                        new Pumper(imageInputStream, imageFileOutputStream, true).call();
108                                        ret = imageFile.getName();
109                                        classImages.put(obj.getClass(), ret);
110                                        return ret;
111                                }
112                        }
113                }
114                return ret==null ? "dhtmlgoodies_folder.gif" : ret;
115        }
116        
117        /**
118         * @param element
119         * @return Object ID.
120         */
121        public Object getId(Object element) {
122                return identityManager.getIdentity(element);
123        }
124        
125        /**
126         * Renders outline for the current object to a writer.
127         * @param obj Source object.
128         * @param writer Output writer.
129         * @throws RenderingException
130         */
131        public void renderOutline(Object obj, Writer writer) throws RenderingException {
132                renderOutline(obj, writer, false);
133        }
134 
135        /**
136         * Renders outline for the current object to a writer.
137         * @param obj Source object.
138         * @param writer Output writer.
139         * @param http If true outline shall be rendered with use
140         * of AJAX, which is useful for large trees.
141         * @throws RenderingException
142         */
143        public void renderOutline(Object obj, Writer writer, boolean http) throws RenderingException {
144                WriterRenderer renderer = ConvertingService.convert(obj, WriterRenderer.class);
145                if (renderer!=null) {
146                        renderer.render(writer, env, context, http ? "outline_http" : "outline", locale, getOutputDir());
147                }
148        }        
149        
150        /**
151         * Renders details and contents without rendering outline.
152         * This method can be used for model elements not appearing
153         * in the outline, but referenced by objects appearing in the
154         * outline.
155         * @param obj Source object.
156         * @param http If true outline shall be rendered with use
157         * of AJAX, which is useful for large trees.
158         * @throws RenderingException
159         */
160        public void renderDetailsAndContents(Object obj) throws RenderingException {
161                if (obj!=null) {
162                        IdentityManager<?> identityManager = context.lookup(IdentityManager.class);
163                        Object id = identityManager.getIdentity(obj);
164                        FileRenderer renderer = ConvertingService.convert(obj, FileRenderer.class);
165                        if (renderer!=null) {
166                                File detailsOut = new File(outputDir, "e"+id+".html");
167                                if (!detailsOut.exists()) {
168                                        renderer.render(detailsOut, env, context, null, locale);
169                                }
170                                File contentsOut = new File(outputDir, "e"+id+"_contents.html");
171                                if (!contentsOut.exists()) {
172                                        renderer.render(contentsOut, env, context, http ? CONTENTS_HTTP : CONTENTS, locale);
173                                }
174                        } else {
175                                throw new NullPointerException("Renderer not found");
176                        }
177                }
178        }
179        
180        /**
181         * Renders details and contents without rendering outline. Returns
182         * link to the file and possibly anchor within the file.
183         * This method can be used for model elements not appearing
184         * in the outline, but referenced by objects appearing in the
185         * outline.
186         * @param obj Source object.
187         * @param http If true outline shall be rendered with use
188         * of AJAX, which is useful for large trees.
189         * @throws RenderingException
190         */
191        public String renderAndLink(Object obj) throws RenderingException {
192                if (obj!=null) {
193                        CompositePart part = ConvertingService.convert(obj, CompositePart.class, context, obj.getClass().getClassLoader());
194                        String tail="";
195                        if (part!=null) {
196                                String anchor = part.getAnchor();
197                                if (anchor!=null) {
198                                        tail = "#"+part.getAnchor();
199                                }
200                                obj = part.getComposite();
201                        }
202                        IdentityManager<?> identityManager = context.lookup(IdentityManager.class);
203                        Object id = identityManager.getIdentity(obj);
204//                        int bucketNo = Math.abs(id.hashCode() % BUCKETS);
205//                        File bucketDir = new File(outputDir, "D"+bucketNo);
206//                        if (!bucketDir.exists()) {
207//                                bucketDir.mkdirs();
208//                        }
209                        FileRenderer renderer = ConvertingService.convert(obj, FileRenderer.class);
210                        if (renderer!=null) {
211                                File detailsOut = new File(outputDir, "e"+id+".html");
212                                if (!detailsOut.exists()) {
213                                        renderer.render(detailsOut, env, context, null, locale);
214                                }
215                                File contentsOut = new File(outputDir, "e"+id+"_contents.html");
216                                if (!contentsOut.exists()) {
217                                        renderer.render(contentsOut, env, context, http ? CONTENTS_HTTP : CONTENTS, locale);
218                                }
219                                return /* bucketDir.getName()+"/"+ */ detailsOut.getName()+tail;
220                        } else {
221                                throw new NullPointerException("Renderer not found");
222                        }
223                }
224                return null;
225        }
226        
227        /**
228         * Tries to render object "inline" (using WriterRenderer). If object cannot be converted
229         * to WriterRenderer, it gets converted to FileRenderer and a link is rendered.
230         * @param obj Source object.
231         * @throws RenderingException
232         */
233        public String render(Object obj, String profile) throws RenderingException {
234                if (obj==null) {
235                        return "";
236                }
237                
238                WriterRenderer wr = ConvertingService.convert(obj, WriterRenderer.class);
239                if (wr!=null) {
240                        StringWriter writer = new StringWriter();
241                        try {
242                                boolean rendered;
243                                try {
244                                        rendered = wr.render(writer, env, context, profile, locale, outputDir);
245                                } finally {
246                                        writer.close();
247                                }
248                                if (rendered) {
249                                        return writer.toString();
250                                }
251                        } catch (IOException e) {
252                                throw new RenderingException(e);
253                        }
254                }
255                
256                // Default inlining - link.
257                return "<a href=\""+renderAndLink(obj)+"\">"+obj+"</a>";
258        }
259        
260        public boolean isBlank(String str) {
261                return str==null || str.trim().length()==0;
262        }
263        
264        public String null2blank(String str) {
265                return str==null ? "" : str;
266        }
267        
268        public String escapeHtml(String txt) {
269                if (txt==null) {
270                        return null;
271                }
272                
273                StringBuffer ret = new StringBuffer();
274                char[] chars=txt.toCharArray();
275                for (int i=0; i<chars.length; ++i) {
276                        switch (chars[i]) {
277                        case '<':
278                                ret.append("&lt;");
279                                break;
280                        case '>':
281                                ret.append("&gt;");
282                                break;
283                        case '&':
284                                if (i<chars.length-1 && '#'==chars[i+1]) { // Do not double-escape (&#...;)
285                                        ret.append(chars[i]);
286                                } else {
287                                        ret.append("&amp;");
288                                }
289                                break;
290                        case '\'':
291                                ret.append("&#039;");
292                                break;
293                        case '\\':
294                                ret.append("&#092;");
295                                break;
296                        case '\"':
297                                ret.append("&quot;");
298                                break;
299                        default:
300                                ret.append("&#"+((int) chars[i])+";");
301                        }
302                }
303                return ret.toString();
304        }
305        
306        /**
307         * Creates object. This method is a workaround for JXP classloader issues.
308         * @param className
309         * @param classLoader
310         * @param args
311         * @return
312         * @throws ClassNotFoundException 
313         * @throws SecurityException 
314         * @throws IllegalAccessException 
315         * @throws InstantiationException 
316         */
317        public Object createObject(String className, ClassLoader classLoader, Object... args) throws Exception {
318                Class<?> clazz = classLoader.loadClass(className);
319                if (args==null || args.length==0) {
320                        return clazz.newInstance(); 
321                }
322                
323                Z: for (Constructor<?> c: clazz.getConstructors()) {
324                        Class<?>[] parameterTypes = c.getParameterTypes();
325                        if (parameterTypes.length==args.length) {
326                                for (int i=0; i<parameterTypes.length; ++i) {
327                                        if (args[i]!=null && !parameterTypes[i].isInstance(args[i])) {
328                                                continue Z;
329                                        }
330                                }
331                                return c.newInstance(args);
332                        }
333                }
334                
335                throw new NoSuchMethodException("Could not find appropriate constructor for "+className+" with "+args.length+" arguments.");
336        }
337        
338        /**
339         * JXP has issues with class loading. This method is a workaround.
340         * @param source Source object.
341         * @param className Target class.
342         * @return
343         * @throws ClassNotFoundException 
344         */
345        public Object convert(Object source, String targetType) throws ClassNotFoundException {
346                ClassLoader classLoader = DuckConverterFactory.getChildClassLoader(source.getClass().getClassLoader(), getClass().getClassLoader());
347                if (classLoader == null) {
348                        classLoader = getClass().getClassLoader();
349                }
350                return ConvertingService.convert(source, classLoader.loadClass(targetType), classLoader);
351        }
352        
353        /**
354         * Sets object attribute.
355         * @param target Target object.
356         * @param name
357         * @param value
358         * @return previous attribute value.
359         */
360        public Object setAttribute(Object target, String name, Object value) {
361                synchronized (attributes) {
362                        Map<String, Object> am = attributes.get(target);
363                        if (am==null) {
364                                am = new HashMap<String, Object>();
365                                attributes.put(target, am);
366                        }                        
367                        return am.put(name, value);                        
368                }
369        }
370        
371        /**
372         * Sets object attribute if it was not present.
373         * @param target Target object.
374         * @param name
375         * @param value
376         */
377        public Object setAttributeIfAbsent(Object target, String name, Object value) {
378                synchronized (attributes) {
379                        Map<String, Object> am = attributes.get(target);
380                        if (am==null) {
381                                am = new HashMap<String, Object>();
382                                attributes.put(target, am);
383                        }                        
384                        if (!am.containsKey(name)) {
385                                return am.put(name, value);
386                        }
387                        return null;
388                }
389        }
390        
391        /**
392         * Replaces object attribute value only if it is present.
393         * @param target Target object.
394         * @param name
395         * @param value
396         */
397        public Object replaceAttribute(Object target, String name, Object value) {
398                synchronized (attributes) {
399                        Map<String, Object> am = attributes.get(target);
400                        if (am==null) {
401                                am = new HashMap<String, Object>();
402                                attributes.put(target, am);
403                        }                        
404                        if (am.containsKey(name)) {
405                                return am.put(name, value);
406                        }
407                        return null;
408                }
409        }
410        
411        public Object removeAttribute(Object target, String name) {
412                synchronized (attributes) {
413                        Map<String, Object> am = attributes.get(target);
414                        if (am!=null) {
415                                return am.remove(name);
416                        }                        
417                        return null;
418                }
419        }
420        
421        public Object getAttribute(Object target, String name) {
422                synchronized (attributes) {
423                        Map<String, Object> am = attributes.get(target);
424                        if (am!=null) {
425                                return am.get(name);
426                        }                        
427                        return null;
428                }
429        }
430        
431        public Object getAttribute(Object target, String name, String defaultValue) {
432                synchronized (attributes) {
433                        Map<String, Object> am = attributes.get(target);
434                        if (am!=null) {
435                                return am.get(name);
436                        }                        
437                        return defaultValue;
438                }
439        }
440        
441        /**
442         * Renders Wiki style link url[|name] as HTML link.
443         * @param wikiLink
444         * @return
445         */
446        public String wikiLink(String wikiLink) {
447                if (wikiLink==null) {
448                        return "";
449                }
450                
451                int idx = wikiLink.indexOf("|");
452                if (idx==-1) {
453                        return "<a href=\""+wikiLink+"\">"+wikiLink+"</a>";
454                }
455 
456                return "<a href=\""+wikiLink.substring(0, idx)+"\">"+wikiLink.substring(idx+1)+"</a>";                
457        }
458}

[all classes][com.hammurapi.render]
EMMA 2.0.5312 EclEmma Fix 2 (C) Vladimir Roubtsov