KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > module > builders > Images


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.module.builders;
11
12 import java.util.*;
13
14 import org.mmbase.core.event.NodeEvent;
15 import org.mmbase.module.core.*;
16 import org.mmbase.util.*;
17 import org.mmbase.util.images.*;
18 import org.mmbase.util.functions.*;
19 import org.mmbase.util.logging.*;
20 import org.mmbase.util.xml.UtilReader;
21
22 import javax.servlet.http.HttpServletResponse JavaDoc;
23 import javax.servlet.http.HttpServletRequest JavaDoc;
24 import javax.servlet.ServletContext JavaDoc;
25
26 /**
27  * If this class is used as the class for your builder, then an 'handle' byte field is assumed to
28  * contain an image. You builder will work together with 'icaches', and with imagemagick (or jai).
29  *
30  * This means that is has the following properties: ImageConvertClass,
31  * ImageConvert.ConverterCommand, ImageConvert.ConverterRoot and MaxConcurrentRequests
32  *
33  * @author Daniel Ockeloen
34  * @author Rico Jansen
35  * @author Michiel Meeuwissen
36  * @version $Id: Images.java,v 1.117 2006/08/15 09:55:54 nklasens Exp $
37  */

38 public class Images extends AbstractImages {
39
40     private static final Logger log = Logging.getLoggerInstance(Images.class);
41
42     // This cache connects templates (or ckeys, if that occurs), with node numbers,
43
// to avoid querying icaches.
44
private CKeyCache templateCacheNumberCache = new CKeyCache(500) {
45         public String JavaDoc getName() { return "CkeyNumberCache"; }
46         public String JavaDoc getDescription() { return "Connection between image conversion templates and icache node numbers"; }
47         };
48
49     public final static Parameter[] CACHE_PARAMETERS = {
50         new Parameter("template", String JavaDoc.class)
51     };
52
53
54     public final static Parameter[] CACHEDNODE_PARAMETERS = CACHE_PARAMETERS;
55     public final static Parameter[] HEIGHT_PARAMETERS = CACHE_PARAMETERS;
56     public final static Parameter[] WIDTH_PARAMETERS = CACHE_PARAMETERS;
57     public final static Parameter[] DIMENSION_PARAMETERS = CACHE_PARAMETERS;
58
59
60     public final static Parameter[] GUI_PARAMETERS = {
61         new Parameter.Wrapper(MMObjectBuilder.GUI_PARAMETERS),
62         new Parameter("template", String JavaDoc.class)
63     };
64
65
66     public Images() {
67         templateCacheNumberCache.putCache();
68     }
69
70     /**
71      * Supposed image type if not could be determined (configurable)
72      */

73     protected String JavaDoc defaultImageType = "jpg";
74
75
76     /**
77      * Read configurations (imageConvertClass, maxConcurrentRequest),
78      * checks for 'icaches', inits the request-processor-pool.
79      */

80     public boolean init() {
81         if (oType != -1) return true; // inited already
82

83         if (!super.init()) return false;
84
85         String JavaDoc tmp = getInitParameter("DefaultImageType");
86
87         if (tmp != null) {
88             defaultImageType = tmp;
89         }
90
91         ImageCaches imageCaches = (ImageCaches) mmb.getMMObject("icaches");
92         if(imageCaches == null) {
93             log.warn("Builder with name 'icaches' wasn't loaded. Cannot do image-conversions.");
94         }
95
96         Map map = getInitParameters("mmbase/imaging");
97         map.put("configfile", getConfigResource());
98
99         Factory.init(map, imageCaches);
100
101         return true;
102     }
103
104     /**
105      * The executeFunction of this builder adds the 'cache' function.
106      * The cache function accepts a conversion template as argument and returns the cached image
107      * node number. Using this you order to pre-cache an image.
108      *
109      * @since MMBase-1.6
110      */

111     protected Object JavaDoc executeFunction(MMObjectNode node, String JavaDoc function, List args) {
112         if (log.isDebugEnabled()) {
113             log.debug("executeFunction " + function + "(" + args + ") of images builder on node " + node.getNumber());
114         }
115         if ("info".equals(function)) {
116             List empty = new ArrayList();
117             Map info = (Map) super.executeFunction(node, function, empty);
118             info.put("cache", "" + CACHE_PARAMETERS + " The node number of the cached converted image (icaches node)");
119             if (args == null || args.size() == 0) {
120                 return info;
121             } else {
122                 return info.get(args.get(0));
123             }
124         } else if ("cache".equals(function)) {
125             if (args == null || args.size() < 1) {
126                 throw new RuntimeException JavaDoc("Images cache functions needs 1 argument (now: " + args + ")");
127             }
128             return new Integer JavaDoc(getCachedNode(node, (String JavaDoc) args.get(0)).getNumber());
129         } else if ("cachednode".equals(function)) {
130             try {
131                 return getCachedNode(node, (String JavaDoc) args.get(0));
132             } catch (Exception JavaDoc e) {
133                 log.error(e.getMessage());
134                 log.error(Logging.stackTrace(e));
135                 return null;
136             }
137         } else if ("height".equals(function)) {
138             if (args.size() == 0) {
139                 return new Integer JavaDoc(getDimension(node).getHeight());
140             } else {
141                 return new Integer JavaDoc(getDimension(node, (String JavaDoc) args.get(0)).getHeight());
142             }
143         } else if ("width".equals(function)) {
144             if (args.size() == 0) {
145                 return new Integer JavaDoc(getDimension(node).getWidth());
146             } else {
147                 return new Integer JavaDoc(getDimension(node, (String JavaDoc) args.get(0)).getWidth());
148             }
149         } else if ("dimension".equals(function)) {
150             if (args.size() == 0) {
151                 return getDimension(node);
152             } else {
153                 return getDimension(node, (String JavaDoc) args.get(0));
154             }
155         } else {
156             return super.executeFunction(node, function, args);
157         }
158     }
159     /**
160      * @since MMBase-1.7.4
161      */

162     protected Dimension getDimension(MMObjectNode node, String JavaDoc template) {
163         if (template == null || template.equals("")) { // no template given, return dimension of node itself.
164
return getDimension(node);
165         }
166         ImageCaches imageCaches = (ImageCaches) mmb.getMMObject("icaches");
167         if(imageCaches == null) {
168             throw new UnsupportedOperationException JavaDoc("The 'icaches' builder is not availabe");
169         }
170         MMObjectNode icacheNode = imageCaches.getCachedNode(node.getNumber(), template);
171         if (icacheNode != null) {
172             return imageCaches.getDimension(icacheNode);
173         } else {
174             // no icache available? Only return prediction.
175
return Imaging.predictDimension(getDimension(node), Imaging.parseTemplate(template));
176         }
177     }
178
179
180     /**
181      * Returns a icache node for given image node and conversion template. If such a node does not exist, it is created.
182      *
183      * @since MMBase-1.8
184      */

185     public MMObjectNode getCachedNode(MMObjectNode node, String JavaDoc template) {
186         ImageCaches imageCaches = (ImageCaches) mmb.getMMObject("icaches");
187         if(imageCaches == null) {
188             throw new UnsupportedOperationException JavaDoc("The 'icaches' builder is not availabe");
189         }
190
191         MMObjectNode icacheNode = imageCaches.getCachedNode(node.getNumber(), template);
192
193         if (icacheNode == null) {
194             icacheNode = imageCaches.getNewNode("imagesmodule");
195             String JavaDoc ckey = Factory.getCKey(node.getNumber(), template).toString();
196             icacheNode.setValue(Imaging.FIELD_CKEY, ckey);
197             icacheNode.setValue(ImageCaches.FIELD_ID, node.getNumber());
198             if (imageCaches.storesDimension() || imageCaches.storesFileSize()) {
199                 Dimension dimension = getDimension(node);
200                 Dimension predictedDimension = Imaging.predictDimension(dimension, Imaging.parseTemplate(template));
201                 log.debug("" + dimension + " " + template + " --> " + predictedDimension);
202                 if (imageCaches.storesDimension()) {
203                     icacheNode.setValue(FIELD_HEIGHT, predictedDimension.getHeight());
204                     icacheNode.setValue(FIELD_WIDTH, predictedDimension.getWidth());
205                 }
206                 if (imageCaches.storesFileSize()) {
207                     icacheNode.setValue(FIELD_FILESIZE, Imaging.predictFileSize(dimension, getFileSize(node), predictedDimension));
208                 }
209             }
210             int icacheNumber = icacheNode.insert("imagesmodule");
211             log.debug("Inserted " + icacheNode);
212             if (icacheNumber < 0) {
213                 throw new RuntimeException JavaDoc("Can't insert cache entry id=" + node.getNumber() + " key=" + template);
214             }
215         }
216         return icacheNode;
217     }
218
219
220     /**
221      * The GUI-indicator of an image-node also needs a res/req object.
222      * @since MMBase-1.6
223      */

224     protected String JavaDoc getGUIIndicatorWithAlt(MMObjectNode node, String JavaDoc alt, Parameters args) {
225         int num = node.getNumber();
226         if (num < 0) { // image servlet cannot handle uncommited images..
227
return "...";
228         }
229
230         String JavaDoc ses = getSession(args, num);
231         StringBuffer JavaDoc servlet = new StringBuffer JavaDoc();
232         HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) args.get(Parameter.REQUEST);
233         if (req != null) {
234             ServletContext JavaDoc sx = MMBaseContext.getServletContext();
235             if (sx != null && "true".equals(sx.getInitParameter("mmbase.taglib.url.makerelative"))) {
236                 servlet.append(getServletPath(UriParser.makeRelative(new java.io.File JavaDoc(req.getServletPath()).getParent(), "/")));
237             } else {
238                 servlet.append(getServletPath());
239             }
240         } else {
241             servlet.append(getServletPath());
242         }
243         servlet.append(usesBridgeServlet && ses != null ? "session=" + ses + "+" : "");
244         String JavaDoc template = (String JavaDoc) args.get("template");
245         if (template == null) template = ImageCaches.GUI_IMAGETEMPLATE;
246         MMObjectNode icache = getCachedNode(node, template);
247         if (icache == null) {
248             throw new RuntimeException JavaDoc("No icache found!");
249         }
250         String JavaDoc imageThumb = servlet.toString() + (icache != null ? "" + icache.getNumber() : "");
251
252         servlet.append(node.getNumber());
253         String JavaDoc image;
254         HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) args.get(Parameter.RESPONSE);
255         if (res != null) {
256             imageThumb = res.encodeURL(imageThumb);
257             image = res.encodeURL(servlet.toString());
258         } else {
259             image = servlet.toString();
260         }
261         String JavaDoc heightAndWidth;
262         ImageCaches imageCaches = (ImageCaches) mmb.getMMObject("icaches");
263         if (imageCaches != null && imageCaches.storesDimension()) {
264             Dimension dim = imageCaches.getDimension(icache);
265             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
266             if(dim.getHeight() > 0) {
267                 buf.append("height=\"").append(dim.getHeight()).append("\" ");
268             } else {
269                 log.warn("Found non-positive height.");
270             }
271             if (dim.getWidth() > 0) {
272                 buf.append("width=\"").append(dim.getWidth()).append("\" ");
273             } else {
274                 log.warn("Found non-positive width.");
275             }
276             heightAndWidth = buf.toString();
277         } else {
278             heightAndWidth = "";
279         }
280
281         String JavaDoc title;
282         String JavaDoc field = (String JavaDoc) args.get("field");
283         if (field == null || field.equals("")) {
284             // gui for the node itself.
285
title = "";
286         } else {
287             if (storesDimension()) {
288                 title = " title=\"" + getMimeType(node) + " " + getDimension(node) + "\"";
289             } else {
290                 title = " title=\"" + getMimeType(node) + "\"";
291             }
292         }
293
294         return
295             "<a HREF=\"" + image + "\" class=\"mm_gui\" onclick=\"window.open(this.href); return false;\"><img SRC=\"" + imageThumb + "\" " +
296             heightAndWidth +
297             "border=\"0\" alt=\"" +
298             org.mmbase.util.transformers.Xml.XMLAttributeEscape(alt, '\"') +
299             "\"" + title + " /></a>";
300     }
301
302     // javadoc inherited
303
protected String JavaDoc getSGUIIndicatorForNode(MMObjectNode node, Parameters args) {
304         return getGUIIndicatorWithAlt(node, node.getStringValue("title"), args);
305     }
306
307
308     // javadoc inherited
309
public String JavaDoc getDefaultImageType() {
310         return defaultImageType;
311     }
312
313     // javadoc inherited
314
public boolean commit(MMObjectNode node) {
315         Collection changed = node.getChanged();
316         // look if we need to invalidate the image cache...
317
boolean imageCacheInvalid = changed.contains("handle");
318         // do the commit
319
if(super.commit(node)) {
320             // when cache is invalid, invalidate
321
if(imageCacheInvalid) {
322                 invalidateImageCache(node);
323                 templateCacheNumberCache.remove(node.getNumber());
324             }
325             return true;
326         }
327         return false;
328     }
329
330     /**
331      * Override the MMObjectBuilder removeNode, to invalidate the Image Cache AFTER a deletion of the
332      * image node.
333      * Remove a node from the cloud.
334      * @param node The node to remove.
335      */

336     public void removeNode(MMObjectNode node) {
337         invalidateImageCache(node);
338         templateCacheNumberCache.remove(node.getNumber());
339         super.removeNode(node);
340     }
341
342
343
344     /* (non-Javadoc)
345      * @see org.mmbase.module.core.MMObjectBuilder#notify(org.mmbase.core.event.NodeEvent)
346      */

347     public void notify(NodeEvent event) {
348         if (log.isDebugEnabled()) {
349             log.debug("Changed " + event.getMachine() + " " + event.getNodeNumber() +
350                 " " + event.getBuilderName() + " "+ NodeEvent.newTypeToOldType(event.getType()));
351         }
352         invalidateTemplateCacheNumberCache(event.getNodeNumber());
353         super.notify(event);
354     }
355
356
357     /**
358      * Invalidate the Image Cache, if there is one, for a specific ImageNode
359      * @param node The image node, which is the original
360      */

361     private void invalidateImageCache(MMObjectNode node) {
362         ImageCaches icache = (ImageCaches) mmb.getMMObject("icaches");
363         if(icache != null) {
364             // we have a icache that is active...
365
icache.invalidate(node);
366         }
367     }
368
369     /**
370      * @javadoc
371      */

372     void invalidateTemplateCacheNumberCache(int number) {
373         templateCacheNumberCache.remove(number);
374     }
375
376     /**
377      * @since MMBase-1.7
378      */

379     void invalidateTemplateCacheNumberCache(String JavaDoc ckey) {
380         templateCacheNumberCache.remove(ckey);
381     }
382
383
384
385
386 }
387
388
Popular Tags