get rid of long standing bug which caused links (href's) with ampersands (&) in them...
[mir.git] / source / mircoders / entity / EntityContent.java
1 /*
2  * Copyright (C) 2001, 2002  The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package mircoders.entity;
33
34 import java.lang.*;
35 import java.io.*;
36 import java.util.*;
37 import java.sql.*;
38 import java.lang.reflect.*;
39
40 import freemarker.template.*;
41
42 import mir.entity.*;
43 import mir.misc.*;
44 import mir.media.*;
45 import mir.storage.*;
46
47 import mircoders.storage.*;
48
49 /**
50  * this class implements mapping of one line of the database table content
51  * to a java object
52  *
53  * @version $Id: EntityContent.java,v 1.9.2.3 2002/11/26 01:51:10 mh Exp $
54  * @author rk, mir-coders group
55  *
56  */
57
58
59 public class EntityContent extends Entity
60 {
61
62   String mirconf_extLinkName  = MirConfig.getProp("Producer.ExtLinkName");
63   String mirconf_intLinkName  = MirConfig.getProp("Producer.IntLinkName");
64   String mirconf_mailLinkName = MirConfig.getProp("Producer.MailLinkName");
65   String mirconf_imageRoot    = MirConfig.getProp("Producer.ImageRoot");
66
67   //this should always be transient i.e it can never be stored in the db
68   //or ObjectStore. (so the ObjectStore should only be caching what comes
69   //directly out of the DB. @todo confirm this with rk. -mh
70   HashMap _entCache = new HashMap();
71   Boolean _hasMedia = null;
72
73         // constructors
74
75         public EntityContent()
76         {
77                 super();
78     //content_data is now filed-type "text"
79                 //streamedInput = new ArrayList();
80                 //streamedInput.add("content_data");
81         }
82
83         public EntityContent(StorageObject theStorage) {
84                 this();
85                 setStorage(theStorage);
86         }
87
88         //
89         // methods
90
91  /**
92         * set is_produced flag for the article
93         */
94
95         public void setProduced(boolean yesno) throws StorageObjectException
96         {
97                 String value = (yesno) ? "1":"0";
98                 if (value.equals( getValue("is_produced") )) return;
99
100     Connection con=null;Statement stmt=null;
101     String sql = "update content set is_produced='" + value + "' where id='" + getId()+"'";
102                 try {
103                         con = theStorageObject.getPooledCon();
104                         /** @todo should be preparedStatement: faster!! */
105                         stmt = con.createStatement();
106                         theStorageObject.executeUpdate(stmt,sql);
107                 } catch (StorageObjectException e) {
108             throwStorageObjectException(e, "\n -- set produced failed");
109                 } catch (SQLException e) {
110             throwStorageObjectException(e, "\n -- set produced failed");
111                 } finally {
112                         theStorageObject.freeConnection(con,stmt);
113                 }
114         }
115
116
117  /**
118         * make openposting to newswire
119         */
120
121         public void newswire() throws StorageObjectException
122         {
123                 String sql = "update content set to_article_type='1', is_produced='0' where id='" + getId()+"'";
124                 try {
125                                 theStorageObject.executeUpdate(sql);
126                 } catch (StorageObjectException e) {
127             throwStorageObjectException(e, "\n -- newswire failed");
128                 } catch (SQLException e) {
129             throwStorageObjectException(e, "\n -- newswire failed");
130                 }
131         }
132
133
134  /**
135         * dettach from media
136         */
137         public void dettach(String cid,String mid) throws StorageObjectException
138         {
139                 if (mid!=null){
140                         try{
141                                 DatabaseContentToMedia.getInstance().delete(cid,mid);
142                         } catch (Exception e){
143                 throwStorageObjectException(e, "\n -- failed to get instance");
144                         }
145                         //set Content to unproduced
146                         setProduced(false);
147                 }
148         }
149
150  /**
151         * attach to media
152         */
153
154         public void attach(String mid) throws StorageObjectException
155         {
156                 if (mid!=null) {
157                         //write media-id mid and content-id in table content_x_media
158                         try{
159                                 DatabaseContentToMedia.getInstance().addMedia(getId(),mid);
160                         } catch(StorageObjectException e){
161                                 throwStorageObjectException(e, "attach: could not get the instance");
162                         }
163                         //set Content to unproduced
164                         setProduced(false);
165                 }       else {
166                         theLog.printError("EntityContent: attach without mid");
167                 }
168         }
169
170         /**
171          * overridden method getValue to include formatted date into every
172          * entityContent
173          */
174
175         public String getValue(String field)
176   {
177     String returnField = null;
178     if (field!=null)
179     {
180       if (field.equals("date_formatted") || field.equals("webdb_create_short") )
181       {
182                   if (hasValueForField("date"))
183         returnField = StringUtil.webdbDate2readableDate(getValue("webdb_create"));
184                 }
185       else if (field.equals("description_parsed"))
186         returnField = getDescriptionParsed();
187       else if (field.equals("description_sentence"))
188         returnField = getDescriptionSentence();
189       else if (field.equals("content_data_parsed"))
190         returnField = getContentDataParsed();
191       else
192         return super.getValue(field);
193     }
194     return returnField;
195         }
196
197   public TemplateModel get(java.lang.String key) throws TemplateModelException
198   {
199     if (key!=null) {
200       if (_entCache.containsKey(key)) {
201         return (TemplateModel)_entCache.get(key);
202       }
203       if (key.equals("to_comments")) {
204         try {
205           _entCache.put(key, getComments());
206           return (TemplateModel)_entCache.get(key);
207         } catch (Exception ex) {
208           theLog.printWarning("-- getComments: could not fetch data " + ex.toString());
209           throw new TemplateModelException(ex.toString());
210         }
211       }
212       if (key.equals("to_media_images")) {
213         try {
214           _entCache.put(key, getImagesForContent());
215           return (TemplateModel)_entCache.get(key);
216         }
217         catch (Exception ex) {
218           theLog.printWarning("-- getImagesForContent: could not fetch data " + ex.toString());
219           throw new TemplateModelException(ex.toString());
220         }
221       }
222       if (key.equals("to_media_audio")) {
223         try {
224           _entCache.put(key, getAudioForContent());
225           return (TemplateModel)_entCache.get(key);
226         }
227         catch (Exception ex) {
228           theLog.printWarning("-- getAudioForContent: could not fetch data " + ex.toString());
229           throw new TemplateModelException(ex.toString());
230         }
231       }
232       if (key.equals("to_media_video")) {
233         try {
234           _entCache.put(key, getVideoForContent());
235           return (TemplateModel)_entCache.get(key);
236         }
237         catch (Exception ex) {
238           theLog.printWarning("-- getVideoForContent: could not fetch data " + ex.toString());
239           throw new TemplateModelException(ex.toString());
240         }
241       }
242       if (key.equals("to_media_other")) {
243         try {
244           _entCache.put(key, getOtherMediaForContent());
245           return (TemplateModel)_entCache.get(key);
246         }
247         catch (Exception ex) {
248           theLog.printWarning("-- getOtherMediaForContent: could not fetch data " + ex.toString());
249           throw new TemplateModelException(ex.toString());
250         }
251       }
252       else if (key.equals("to_media_icon")) {
253         try {
254           _entCache.put(key, getUploadedMediaForNewswire());
255           return (TemplateModel)_entCache.get(key);
256         }
257         catch (Exception ex) {
258           theLog.printWarning("-- getUploadedMediaForNewswire: could not fetch data " + ex.toString());
259           throw new TemplateModelException(ex.toString());
260         }
261       }
262       else if (key.equals("to_topics")) {
263         try {
264           _entCache.put(key, 
265                         DatabaseContentToTopics.getInstance().getTopics(this));
266           return (TemplateModel)_entCache.get(key);
267         }
268         catch (Exception ex) {
269           theLog.printWarning("-- getTopics: could not fetch data " + ex.toString());
270           throw new TemplateModelException(ex.toString());
271         }
272       }
273       else {
274         return new SimpleScalar(getValue(key));
275       }
276
277     }
278     return null;
279   }
280
281
282
283
284         /**
285          * overridden method setValues to patch creator_main_url
286          */
287         public void setValues(HashMap theStringValues) {
288                 if (theStringValues != null) {
289                         if (theStringValues.containsKey("creator_main_url")){
290                                 if (((String)theStringValues.get("creator_main_url")).equalsIgnoreCase("http://")){
291                                         theStringValues.remove("creator_main_url");
292         } else if (!((String)theStringValues.get("creator_main_url")).startsWith("http://")){
293           theStringValues.put("creator_main_url","http://"+((String)theStringValues.get("creator_main_url")));
294         }
295       }
296                 }
297                 super.setValues(theStringValues);
298         }
299
300
301   private String getContentDataParsed() {
302     String returnField = getValue("content_data");
303     if ((returnField!=null) && (returnField.length()>0) ) {
304       returnField=StringUtil.deleteForbiddenTags(returnField);
305       //create http-links and email-links
306       if (getValue("is_html").equals("0")) {
307         returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
308                                             mirconf_mailLinkName,mirconf_extLinkName,
309                                             mirconf_intLinkName);
310       }
311     }
312     return returnField;
313   }
314
315   private String getDescriptionSentence() {
316     String returnField = getValue("description");
317     if (returnField != null && returnField.length()>0) {
318        returnField = StringUtil.removeHTMLTags(returnField);
319        int endOfFirstSentence=StringUtil.findEndOfSentence(returnField,0);
320        if (endOfFirstSentence > 0){
321          returnField = returnField.substring(0,endOfFirstSentence);
322        }
323     }
324     return returnField;
325   }
326
327   private String getDescriptionParsed() {
328     String returnField = getValue("description");
329     if (returnField != null && returnField.length()>0) {
330       returnField = StringUtil.deleteForbiddenTags(returnField);
331       if (getValue("is_html").equals("0")) {
332         returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
333                                             mirconf_mailLinkName,mirconf_extLinkName,
334                                             mirconf_intLinkName);
335       }
336     }
337     return returnField;
338   }
339
340         /**
341          * fetches all the comments belonging to an article
342          *
343          * @return freemarker.template.SimpleList
344          */
345         private EntityList getComments() throws StorageObjectException {
346                 return ((DatabaseContent)theStorageObject).getComments(this);
347         }
348
349   // @todo this needs to optimized. expensive SQL
350   private SimpleHash getUploadedMediaForNewswire()
351     throws StorageObjectException, TemplateModelException
352   {
353     // fetching/setting the images
354     // return to_media_icons
355     String        tinyIcon = null, iconAlt = null;
356     MirMedia      mediaHandler = null;
357     EntityUploadedMedia uploadedMedia;
358     Entity        mediaType;
359     SimpleHash    returnHash = new SimpleHash();
360
361     EntityList upMediaEntityList =
362                     DatabaseContentToMedia.getInstance().getUploadedMedia(this);
363     if (upMediaEntityList!=null && upMediaEntityList.getCount()>=1) {
364
365       for (int n=0; n < upMediaEntityList.size();n++) {
366         uploadedMedia = (EntityUploadedMedia)upMediaEntityList.elementAt(n);
367         mediaType = uploadedMedia.getMediaType();
368         try {
369           mediaHandler = MediaHelper.getHandler( mediaType );
370         } catch (MirMediaException ex) {
371           throw new TemplateModelException(ex.toString());
372         }
373         //the "best" media type to show
374         if (mediaHandler.isVideo()) {
375           tinyIcon = MirConfig.getProp("Producer.Icon.TinyVideo");
376           iconAlt = "Video";
377           break;
378         } else if (mediaHandler.isAudio()) {
379           tinyIcon = MirConfig.getProp("Producer.Icon.TinyAudio");
380           iconAlt = "Audio";
381         } else if (tinyIcon == null && !mediaHandler.isImage()) {
382           tinyIcon = mediaHandler.getTinyIconName();
383           iconAlt = mediaHandler.getIconAltName();
384         }
385
386       }
387       //it only has image(s)
388       if (tinyIcon == null) {
389         tinyIcon = MirConfig.getProp("Producer.Icon.TinyImage");
390         iconAlt = "Image";
391       }
392     // uploadedMedia Entity list is empty.
393     // we only have text
394     } else {
395       tinyIcon = MirConfig.getProp("Producer.Icon.TinyText");
396       iconAlt = "Text";
397     }
398     returnHash.put("tiny_icon", mirconf_imageRoot+"/"+tinyIcon);
399     returnHash.put("icon_alt", iconAlt);
400     return returnHash;
401   }
402
403   private boolean hasMedia() throws StorageObjectException
404   {
405     if (_hasMedia == null) {
406       _hasMedia =
407         new Boolean(DatabaseContentToMedia.getInstance().hasMedia(this));
408     }
409     return _hasMedia.booleanValue();
410   }
411
412   //######## @todo all of the following getBlahForContent should have
413   // and optimized version where LIMIT=1 sql for list view.
414   private EntityList getImagesForContent()
415     throws StorageObjectException, TemplateModelException
416   {
417     if (hasMedia())
418       return DatabaseContentToMedia.getInstance().getImages(this);
419     else
420       return null;
421   }
422
423   private EntityList getAudioForContent()
424     throws StorageObjectException, TemplateModelException
425   {
426     if (hasMedia())
427       return DatabaseContentToMedia.getInstance().getAudio(this) ;
428     else
429       return null;
430   }
431
432   private EntityList getVideoForContent()
433     throws StorageObjectException, TemplateModelException
434   {
435     if (hasMedia())
436       return DatabaseContentToMedia.getInstance().getVideo(this) ;
437     else
438       return null;
439   }
440
441   private EntityList getOtherMediaForContent()
442     throws StorageObjectException, TemplateModelException
443   {
444     if (hasMedia())
445       return DatabaseContentToMedia.getInstance().getOther(this);
446     else
447       return null;
448   }
449
450 }