54d914ed8b23b07a08f8bffeb5d9e21a4672026b
[mir.git] / source / mircoders / localizer / basic / MirBasicDataModelLocalizer.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  any library licensed under the Apache Software License,
22  * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23  * (or with modified versions of the above that use the same license as the above),
24  * and distribute linked combinations including the two.  You must obey the
25  * GNU General Public License in all respects for all of the code used other than
26  * the above mentioned libraries.  If you modify this file, you may extend this
27  * exception to your version of the file, but you are not obligated to do so.
28  * If you do not wish to do so, delete this exception statement from your version.
29  */
30 package mircoders.localizer.basic;
31
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37
38 import mir.config.MirPropertiesConfiguration;
39 import mir.entity.Entity;
40 import mir.entity.adapter.EntityAdapter;
41 import mir.entity.adapter.EntityAdapterDefinition;
42 import mir.entity.adapter.EntityAdapterModel;
43 import mir.entity.adapter.ToManyRelationField;
44 import mir.entity.adapter.ToOneRelationField;
45 import mir.generator.Generator;
46 import mir.generator.GeneratorExc;
47 import mir.generator.GeneratorFailure;
48 import mir.log.LoggerWrapper;
49 import mir.media.MediaHandler;
50 import mir.misc.NumberUtils;
51 import mir.util.JDBCStringRoutines;
52 import mir.util.ParameterExpander;
53 import mir.util.RewindableIterator;
54 import mir.util.StructuredContentParser;
55 import mircoders.entity.EntityUploadedMedia;
56 import mircoders.global.MirGlobal;
57 import mircoders.localizer.MirAdminInterfaceLocalizer;
58 import mircoders.localizer.MirDataModelLocalizer;
59 import mircoders.localizer.MirLocalizerExc;
60 import mircoders.localizer.MirLocalizerFailure;
61 import mircoders.media.MediaHelper;
62 import mircoders.module.ModuleContent;
63 import mircoders.module.ModuleLanguage;
64 import mircoders.storage.DatabaseArticleType;
65 import mircoders.storage.DatabaseAudio;
66 import mircoders.storage.DatabaseBreaking;
67 import mircoders.storage.DatabaseComment;
68 import mircoders.storage.DatabaseCommentStatus;
69 import mircoders.storage.DatabaseContent;
70 import mircoders.storage.DatabaseContentToMedia;
71 import mircoders.storage.DatabaseContentToTopics;
72 import mircoders.storage.DatabaseFilter;
73 import mircoders.storage.DatabaseFilterGroup;
74 import mircoders.storage.DatabaseImageType;
75 import mircoders.storage.DatabaseImages;
76 import mircoders.storage.DatabaseLanguage;
77 import mircoders.storage.DatabaseMediaType;
78 import mircoders.storage.DatabaseMediafolder;
79 import mircoders.storage.DatabaseMessages;
80 import mircoders.storage.DatabaseOther;
81 import mircoders.storage.DatabaseTopics;
82 import mircoders.storage.DatabaseUploadedMedia;
83 import mircoders.storage.DatabaseUsers;
84 import mircoders.storage.DatabaseVideo;
85 import multex.Failure;
86
87 public class MirBasicDataModelLocalizer implements MirDataModelLocalizer {
88   protected LoggerWrapper logger = new LoggerWrapper("Localizer.DataModel");
89   protected MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
90   protected ModuleLanguage languageModule = new ModuleLanguage();
91
92   protected void constructContentAdapterDefinition(EntityAdapterDefinition anEntityAdapterDefinition) throws MirLocalizerFailure, MirLocalizerExc {
93     try {
94       anEntityAdapterDefinition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
95       anEntityAdapterDefinition.addDBDateField("changedate", "webdb_lastchange", configuration.getString("Mir.DefaultTimezone"));
96       anEntityAdapterDefinition.addMirDateField("date", "date", configuration.getString("Mir.DefaultTimezone"));
97
98       anEntityAdapterDefinition.addCalculatedField("lockinguser", new ToOneRelationField("to_locking_user", "id", "user"));
99       anEntityAdapterDefinition.addCalculatedField("is_locked", new ContentToIsLockedField());
100
101       anEntityAdapterDefinition.addCalculatedField("to_topics", new ContentToTopicsField());
102       anEntityAdapterDefinition.addCalculatedField("to_comments", new ContentToCommentsField());
103       anEntityAdapterDefinition.addCalculatedField("language", new ToOneRelationField("to_language", "language", "id"));
104       anEntityAdapterDefinition.addCalculatedField("commentcount", new ContentCommentCountField(" and is_published='1'"));
105       anEntityAdapterDefinition.addCalculatedField("fullcommentcount", new ContentCommentCountField(""));
106
107
108       anEntityAdapterDefinition.addCalculatedField("mediacount", new ContentMediaCountField("uploaded_media", true));
109       anEntityAdapterDefinition.addCalculatedField("fullmediacount", new ContentMediaCountField("uploaded_media", false));
110
111       anEntityAdapterDefinition.addCalculatedField("to_uploaded_media", new ContentToMediaField( "uploadedMedia" ));
112       anEntityAdapterDefinition.addCalculatedField("to_media_images",  new ContentToMediaField( "image" ));
113       anEntityAdapterDefinition.addCalculatedField("to_media_audio", new ContentToMediaField( "audio" ));
114       anEntityAdapterDefinition.addCalculatedField("to_media_video", new ContentToMediaField( "video" ));
115       anEntityAdapterDefinition.addCalculatedField("to_media_other", new ContentToMediaField( "otherMedia" ));
116
117       anEntityAdapterDefinition.addCalculatedField("firstImage",  new ContentToFirstMediaField( "image" ));
118       anEntityAdapterDefinition.addCalculatedField("firstAudio", new ContentToFirstMediaField( "audio" ));
119       anEntityAdapterDefinition.addCalculatedField("firstVideo", new ContentToFirstMediaField( "video" ));
120       anEntityAdapterDefinition.addCalculatedField("firstOther", new ContentToFirstMediaField( "otherMedia" ));
121
122       anEntityAdapterDefinition.addCalculatedField("to_all_uploaded_media", new ContentToMediaField( "uploadedMedia", false));
123       anEntityAdapterDefinition.addCalculatedField("to_all_media_images",  new ContentToMediaField( "image", false));
124       anEntityAdapterDefinition.addCalculatedField("to_all_media_audio", new ContentToMediaField( "audio", false));
125       anEntityAdapterDefinition.addCalculatedField("to_all_media_video", new ContentToMediaField( "video", false));
126       anEntityAdapterDefinition.addCalculatedField("to_all_media_other", new ContentToMediaField( "otherMedia", false));
127       anEntityAdapterDefinition.addCalculatedField("to_media_icon", new ContentToIconField());
128
129       anEntityAdapterDefinition.addCalculatedField("article_type", new ToOneRelationField("to_article_type", "articleType", "id"));
130
131       anEntityAdapterDefinition.addCalculatedField("description_parsed", new FilteredField("description"));
132       anEntityAdapterDefinition.addCalculatedField("content_data_parsed", new FilteredField("content_data"));
133
134       anEntityAdapterDefinition.addCalculatedField("children", new ContentToChildrenField());
135       anEntityAdapterDefinition.addCalculatedField("parent", new ToOneRelationField("to_content", "content", "id"));
136
137       anEntityAdapterDefinition.addCalculatedField("publicurl", new ExpandedField(configuration.getString("Article.PublicUrl")));
138
139       anEntityAdapterDefinition.addCalculatedField("operations",
140           new EntityToSimpleOperationsField(MirGlobal.localizer().adminInterface().simpleArticleOperations()));
141       
142       anEntityAdapterDefinition.addCalculatedField("languagename", new ContentToLanguageNameField());
143
144       anEntityAdapterDefinition.addCalculatedField("is_original", new ContentIsOriginalField());
145       anEntityAdapterDefinition.addCalculatedField("to_original", new ContentToOriginalField());
146       anEntityAdapterDefinition.addCalculatedField("to_translations", new ContentToTranslationsField());
147       anEntityAdapterDefinition.addCalculatedField("to_translation", new ContentToTranslationField());
148
149       anEntityAdapterDefinition.addCalculatedField("previews", new EntityAdapterDefinition.CalculatedField() {
150         public Object getValue(EntityAdapter anEntityAdapter) {
151           try {
152             return MirGlobal.localizer().adminInterface().getPreviewPages(anEntityAdapter);
153           }
154           catch (MirLocalizerExc e) {
155             throw new Failure("Cannot get previews for article", e);
156           }
157         }
158       });
159     }
160     catch (Throwable t) {
161       throw new MirLocalizerFailure(t.getMessage(), t);
162     }
163   }
164
165
166
167   protected void constructCommentAdapterDefinition(EntityAdapterDefinition anEntityAdapterDefinition) throws MirLocalizerFailure {
168     try {
169       anEntityAdapterDefinition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
170       anEntityAdapterDefinition.addCalculatedField("to_content", new ToOneRelationField("to_media", "content", "id"));
171       anEntityAdapterDefinition.addCalculatedField("status", new CommentToStatusField());
172
173       anEntityAdapterDefinition.addCalculatedField("to_uploaded_media", new CommentToMediaField( "uploadedMedia" ));
174       anEntityAdapterDefinition.addCalculatedField("to_media_images",  new CommentToMediaField( "image" ));
175       anEntityAdapterDefinition.addCalculatedField("to_media_audio", new CommentToMediaField( "audio" ));
176       anEntityAdapterDefinition.addCalculatedField("to_media_video", new CommentToMediaField( "video" ));
177       anEntityAdapterDefinition.addCalculatedField("to_media_other", new CommentToMediaField( "otherMedia" ));
178       anEntityAdapterDefinition.addCalculatedField("to_all_uploaded_media", new CommentToMediaField( "uploadedMedia", false));
179       anEntityAdapterDefinition.addCalculatedField("to_all_media_images",  new CommentToMediaField( "image", false));
180       anEntityAdapterDefinition.addCalculatedField("to_all_media_audio", new CommentToMediaField( "audio", false));
181       anEntityAdapterDefinition.addCalculatedField("to_all_media_video", new CommentToMediaField( "video", false));
182       anEntityAdapterDefinition.addCalculatedField("to_all_media_other", new CommentToMediaField( "otherMedia", false));
183
184       anEntityAdapterDefinition.addCalculatedField("publicurl", new ExpandedField(configuration.getString("Comment.PublicUrl")));
185
186       anEntityAdapterDefinition.addCalculatedField("description_parsed", new FilteredField("description"));
187       anEntityAdapterDefinition.addCalculatedField("operations",
188           new EntityToSimpleOperationsField(MirGlobal.localizer().adminInterface().simpleCommentOperations()));
189     }
190     catch (Throwable t) {
191       throw new MirLocalizerFailure(t.getMessage(), t);
192     }
193   }
194
195   public EntityAdapterModel adapterModel() throws MirLocalizerFailure, MirLocalizerExc {
196     EntityAdapterModel result = new EntityAdapterModel();
197
198     try {
199       EntityAdapterDefinition definition;
200
201       definition = new EntityAdapterDefinition();
202       constructContentAdapterDefinition( definition );
203       result.addMapping( "content", DatabaseContent.getInstance(), definition);
204
205       definition = new EntityAdapterDefinition();
206       constructCommentAdapterDefinition( definition );
207       result.addMapping( "comment", DatabaseComment.getInstance(), definition);
208       result.addMapping( "commentStatus", DatabaseCommentStatus.getInstance(), new EntityAdapterDefinition());
209
210       result.addMapping( "articleType", DatabaseArticleType.getInstance(), new EntityAdapterDefinition());
211
212       result.addMapping( "mediaType", DatabaseMediaType.getInstance(), new EntityAdapterDefinition());
213
214
215       definition = new EntityAdapterDefinition();
216       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
217       result.addMapping( "breakingNews", DatabaseBreaking.getInstance(), definition);
218
219       definition = new EntityAdapterDefinition();
220       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
221       result.addMapping( "internalMessage", DatabaseMessages.getInstance(), definition);
222
223       definition = new EntityAdapterDefinition();
224       definition.addCalculatedField("mediafolder", new ToOneRelationField("to_media_folder", "mediaFolder", "id"));
225       definition.addCalculatedField("human_readable_size", new HumanReadableSizeField("value"));
226       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
227       definition.addCalculatedField("info", new MediaToMediaInfoField());
228       result.addMapping( "uploadedMedia", DatabaseUploadedMedia.getInstance(), definition);
229       definition = new EntityAdapterDefinition();
230       definition.addCalculatedField("mediafolder", new ToOneRelationField("to_media_folder", "mediaFolder", "id"));
231       definition.addCalculatedField("human_readable_size", new HumanReadableSizeField("value"));
232       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
233       definition.addCalculatedField("info", new MediaToMediaInfoField());
234       definition.addCalculatedField("big_icon", new MediaToBigIconField());
235       result.addMapping( "image", DatabaseImages.getInstance(), definition);
236       definition = new EntityAdapterDefinition();
237       definition.addCalculatedField("mediafolder", new ToOneRelationField("to_media_folder", "mediaFolder", "id"));
238       definition.addCalculatedField("human_readable_size", new HumanReadableSizeField("value"));
239       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
240       definition.addCalculatedField("info", new MediaToMediaInfoField());
241       definition.addCalculatedField("big_icon", new MediaToBigIconField());
242       result.addMapping( "audio", DatabaseAudio.getInstance(), definition);
243       definition = new EntityAdapterDefinition();
244       definition.addCalculatedField("mediafolder", new ToOneRelationField("to_media_folder", "mediaFolder", "id"));
245       definition.addCalculatedField("human_readable_size", new HumanReadableSizeField("value"));
246       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
247       definition.addCalculatedField("info", new MediaToMediaInfoField());
248       definition.addCalculatedField("big_icon", new MediaToBigIconField());
249       result.addMapping( "video", DatabaseVideo.getInstance(), definition);
250
251       definition = new EntityAdapterDefinition();
252       definition.addCalculatedField("mediafolder", new ToOneRelationField("to_media_folder", "mediaFolder", "id"));
253       definition.addCalculatedField("human_readable_size", new HumanReadableSizeField("value"));
254       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
255       definition.addCalculatedField("info", new MediaToMediaInfoField());
256       definition.addCalculatedField("big_icon", new MediaToBigIconField());
257       result.addMapping( "otherMedia", DatabaseOther.getInstance(), definition);
258
259
260       result.addMapping( "mediaFolder", DatabaseMediafolder.getInstance(), new EntityAdapterDefinition());
261       result.addMapping( "imageType", DatabaseImageType.getInstance(), new EntityAdapterDefinition());
262       result.addMapping( "language", DatabaseLanguage.getInstance(), new EntityAdapterDefinition());
263       result.addMapping( "mediaType", DatabaseMediaType.getInstance(), new EntityAdapterDefinition());
264       result.addMapping( "topic", DatabaseTopics.getInstance(), new EntityAdapterDefinition());
265
266       definition = new EntityAdapterDefinition();
267       definition.addDBDateField("creationdate", "webdb_create", configuration.getString("Mir.DefaultTimezone"));
268       definition.addDBDateField("lastlogindate", "lastlogin", configuration.getString("Mir.DefaultTimezone"));
269       definition.addCalculatedField("structuredProfile", new StructuredContentField("profile"));
270       result.addMapping( "user", DatabaseUsers.getInstance(), definition);
271
272       result.addMapping( "content_x_topic", DatabaseContentToTopics.getInstance(), new EntityAdapterDefinition());
273
274       definition = new EntityAdapterDefinition();
275       definition.addCalculatedField("to_filters",
276           new ToManyRelationField("id", "filter", "filter_group_id", "priority asc"));
277       result.addMapping("filterGroup", DatabaseFilterGroup.getInstance(), definition);
278       definition = new EntityAdapterDefinition();
279       definition.addDBDateField("lasthit", "last_hit", configuration.getString("Mir.DefaultTimezone"));
280       definition.addCalculatedField("to_filter_group",
281           new ToOneRelationField("filter_group_id", "filter_group", "id"));
282       result.addMapping("filter", DatabaseFilter.getInstance(), definition);
283     }
284     catch (Throwable t) {
285       throw new MirLocalizerFailure(t.getMessage(), t);
286     }
287
288     return result;
289   }
290
291   protected class CommentToStatusField implements EntityAdapterDefinition.CalculatedField {
292     public Object getValue(EntityAdapter anEntityAdapter) {
293       try {
294         return anEntityAdapter.getToOneRelation(
295                     "id="+anEntityAdapter.get("to_comment_status"),
296                     "id",
297                     "commentStatus" );
298       }
299       catch (Throwable t) {
300         throw new RuntimeException(t.getMessage());
301       }
302     }
303   }
304
305   protected class EntityToSimpleOperationsField implements EntityAdapterDefinition.CalculatedField {
306     private List operations;
307
308     public EntityToSimpleOperationsField(List anOperations) {
309       operations = anOperations;
310     }
311
312     public Object getValue(EntityAdapter anEntityAdapter) {
313       try {
314         Iterator i = operations.iterator();
315         List availableOperations = new ArrayList();
316
317         while (i.hasNext()) {
318           MirAdminInterfaceLocalizer.MirSimpleEntityOperation operation =
319             (MirAdminInterfaceLocalizer.MirSimpleEntityOperation) i.next();
320
321           if (operation.isAvailable(anEntityAdapter)) {
322             availableOperations.add(operation.getName());
323           }
324         }
325
326         return availableOperations;
327       }
328       catch (Throwable t) {
329         throw new RuntimeException(t.getMessage());
330       }
331     }
332   }
333
334   protected class FilteredField implements EntityAdapterDefinition.CalculatedField {
335     private String fieldName;
336
337     public FilteredField(String aFieldName) {
338       fieldName = aFieldName;
339     }
340
341     public Object getValue(EntityAdapter anEntityAdapter) {
342       try {
343         if (anEntityAdapter.get("is_html")!=null && anEntityAdapter.get("is_html").equals("1")) {
344           return MirGlobal.localizer().producerAssistant().filterHTMLText((String) anEntityAdapter.get(fieldName));
345         }
346                                 return MirGlobal.localizer().producerAssistant().filterNonHTMLText((String) anEntityAdapter.get(fieldName));
347       }
348       catch (Throwable t) {
349         throw new RuntimeException(t.getMessage());
350       }
351     }
352   }
353
354   protected class StructuredContentField implements EntityAdapterDefinition.CalculatedField {
355     private String expression;
356
357     public StructuredContentField(String anExpression) {
358       expression = anExpression;
359     }
360
361     public Object getValue(EntityAdapter anEntityAdapter) {
362       try {
363         return StructuredContentParser.parse(ParameterExpander.evaluateStringExpression(anEntityAdapter, expression));
364       }
365       catch (Throwable t) {
366         throw new RuntimeException(t.getMessage());
367       }
368     }
369   }
370
371   protected class ExpandedField implements EntityAdapterDefinition.CalculatedField {
372     private String expression;
373
374     public ExpandedField(String anExpression) {
375       expression = anExpression;
376     }
377
378     public Object getValue(EntityAdapter anEntityAdapter) {
379       try {
380         return ParameterExpander.expandExpression(anEntityAdapter, expression);
381       }
382       catch (Throwable t) {
383         throw new RuntimeException(t.getMessage());
384       }
385     }
386   }
387
388   protected class EvaluatedField implements EntityAdapterDefinition.CalculatedField {
389     private String expression;
390
391     public EvaluatedField(String anExpression) {
392       expression = anExpression;
393     }
394
395     public Object getValue(EntityAdapter anEntityAdapter) {
396       try {
397         return ParameterExpander.evaluateExpression(anEntityAdapter, expression);
398       }
399       catch (Throwable t) {
400         throw new RuntimeException(t.getMessage());
401       }
402     }
403   }
404
405   protected class ContentToChildrenField implements EntityAdapterDefinition.CalculatedField {
406     public Object getValue(EntityAdapter anEntityAdapter) {
407       try {
408         return anEntityAdapter.getRelation(
409                     "to_content="+anEntityAdapter.get("id"),
410                     "id",
411                     "content" );
412       }
413       catch (Throwable t) {
414         throw new RuntimeException(t.getMessage());
415       }
416     }
417   }
418   public static class MediaInfo {
419     private MediaHandler mediaHandler;
420
421     public MediaInfo(MediaHandler aHandler) {
422       mediaHandler = aHandler;
423     }
424     public String getBigIcon() {
425       if (mediaHandler == null)
426         return "bla";
427                         return mediaHandler.getBigIconName();
428     }
429
430     public String getSmallIcon() {
431       if (mediaHandler == null)
432         return "bla";
433                         return mediaHandler.getTinyIconName();
434     }
435
436     public String getMediaType() {
437       return "";
438     }
439   }
440
441   protected class MediaToMediaInfoField implements EntityAdapterDefinition.CalculatedField {
442     public Object getValue(EntityAdapter anEntityAdapter) {
443       try {
444         MediaHandler mediaHandler = MediaHelper.getHandler(((EntityUploadedMedia) anEntityAdapter.getEntity()).getMediaType());
445
446         return new MediaInfo(mediaHandler);
447       }
448       catch (Throwable t) {
449         throw new RuntimeException(t.getMessage());
450       }
451     }
452   }
453
454   protected class MediaToBigIconField implements EntityAdapterDefinition.CalculatedField {
455     public Object getValue(EntityAdapter anEntityAdapter) {
456       try {
457         return MediaHelper.getHandler(((EntityUploadedMedia) anEntityAdapter.getEntity()).getMediaType()).getBigIconName();
458       }
459       catch (Throwable t) {
460         throw new RuntimeException(t.getMessage());
461       }
462     }
463   }
464
465   protected class ContentToCommentsField implements EntityAdapterDefinition.CalculatedField {
466     private String extracondition;
467     private String order;
468
469     public ContentToCommentsField() {
470       this ( " and is_published='1'", "webdb_create");
471     }
472
473     public ContentToCommentsField(String anExtraCondition, String anOrder) {
474       order = anOrder;
475       extracondition = anExtraCondition;
476     }
477
478     public Object getValue(EntityAdapter anEntityAdapter) {
479       try {
480         return anEntityAdapter.getRelation(
481                     "to_media="+anEntityAdapter.get("id")+" " + extracondition,
482                     order,
483                     "comment" );
484       }
485       catch (Throwable t) {
486         throw new RuntimeException(t.getMessage());
487       }
488     }
489   }
490
491   protected class ContentToTopicsField implements EntityAdapterDefinition.CalculatedField {
492     private String topicCondition;
493     private String topicOrder;
494
495     public ContentToTopicsField() {
496       this(null);
497     }
498
499     public ContentToTopicsField(String aTopicCondition) {
500       this(aTopicCondition, "title");
501     }
502
503     public ContentToTopicsField(String aTopicCondition, String aTopicOrder) {
504       topicCondition = aTopicCondition;
505       topicOrder = aTopicOrder;
506     }
507
508     public Object getValue(EntityAdapter anEntityAdapter) {
509       try {
510
511         ArrayList extraTable = new ArrayList();
512         extraTable.add("content_x_topic cxt");
513         String condition = "cxt.content_id="+anEntityAdapter.get("id")+
514           " and cxt.topic_id=t.id";
515
516         if (topicCondition!=null && topicCondition.length()>0)
517           condition = "(" + topicCondition + ") and " + condition;
518
519         return anEntityAdapter.getComplexRelation("t", extraTable,
520                     condition, topicOrder, "topic" );
521       }
522       catch (Throwable t) {
523         throw new RuntimeException(t.getMessage());
524       }
525     }
526   }
527
528   protected class ContentToMediaField implements EntityAdapterDefinition.CalculatedField {
529     private String definition;
530     private boolean published;
531
532     public ContentToMediaField(String aDefinition, boolean anOnlyPublished) {
533       definition = aDefinition;
534       published = anOnlyPublished;
535     }
536
537     public ContentToMediaField(String aDefinition) {
538       this(aDefinition, true);
539     }
540
541     public Object getValue(EntityAdapter anEntityAdapter) {
542       try {
543         String condition = "cxm.content_id="+ anEntityAdapter.get("id") +
544           " and cxm.media_id = m.id";
545         if (published)
546           condition = "is_published='t' and " + condition;
547
548         List extraTables = new ArrayList();
549         extraTables.add("content_x_media cxm");
550
551         return anEntityAdapter.getComplexRelation("m", extraTables, condition, "id", definition);
552       }
553       catch (Throwable t) {
554         throw new RuntimeException(t.getMessage());
555       }
556     }
557   }
558
559   protected class ContentToFirstMediaField implements EntityAdapterDefinition.CalculatedField {
560     private String definition;
561     private boolean published;
562
563     public ContentToFirstMediaField(String aDefinition, boolean anOnlyPublished) {
564       definition = aDefinition;
565       published = anOnlyPublished;
566     }
567
568     public ContentToFirstMediaField(String aDefinition) {
569       this(aDefinition, true);
570     }
571
572     public Object getValue(EntityAdapter anEntityAdapter) {
573       try {
574         String condition = "cxm.content_id="+ anEntityAdapter.get("id") +
575           " and cxm.media_id = m.id";
576         if (published)
577           condition = "is_published='t' and " + condition;
578
579         List extraTables = new ArrayList();
580         extraTables.add("content_x_media cxm");
581
582         return anEntityAdapter.getComplexToOneRelation("m", extraTables, condition, "id", definition);
583       }
584       catch (Throwable t) {
585         throw new RuntimeException(t.getMessage());
586       }
587     }
588   }
589
590   protected class CommentToMediaField implements EntityAdapterDefinition.CalculatedField {
591     private String definition;
592     private boolean published;
593
594     public CommentToMediaField(String aDefinition, boolean anOnlyPublished) {
595       definition = aDefinition;
596       published = anOnlyPublished;
597     }
598
599     public CommentToMediaField(String aDefinition) {
600       this(aDefinition, true);
601     }
602
603     public Object getValue(EntityAdapter anEntityAdapter) {
604       try {
605
606         String condition = "cxm.comment_id="+ anEntityAdapter.get("id") +
607                   " and cxm.media_id = m.id";
608         if (published)
609            condition = "is_published='t' and " + condition;
610
611         List extraTables = new ArrayList();
612         extraTables.add("comment_x_media cxm");
613         return anEntityAdapter.getComplexRelation("m", extraTables, condition, "id", definition);
614
615       }
616       catch (Throwable t) {
617         throw new RuntimeException(t.getMessage());
618       }
619     }
620   }
621
622   protected class ContentToIconField implements EntityAdapterDefinition.CalculatedField {
623     public Object getValue(EntityAdapter anEntityAdapter) {
624       EntityAdapter media;
625       Entity mediaType;
626       RewindableIterator iterator;
627       Map result;
628       MediaHandler mediaHandler;
629       String tinyIcon;
630       String iconAlt;
631
632       try {
633         iterator = (RewindableIterator) (anEntityAdapter.get("to_uploaded_media"));
634         iterator.rewind();
635
636         tinyIcon = MirGlobal.config().getString("Producer.Icon.TinyText");
637         iconAlt = "Text";
638
639         if (iterator.hasNext()) {
640           media = (EntityAdapter) iterator.next();
641
642           mediaType = ((EntityUploadedMedia) (media.getEntity())).getMediaType();
643           mediaHandler = MediaHelper.getHandler( mediaType );
644
645           tinyIcon = mediaHandler.getTinyIconName();
646           iconAlt = mediaHandler.getIconAltName();
647         }
648       }
649       catch (Throwable t) {
650         logger.error("ContentToIconField: " +t.getMessage());
651         throw new RuntimeException(t.getMessage());
652       }
653
654       result = new HashMap();
655       result.put("tiny_icon", MirGlobal.config().getString("Producer.ImageRoot") + "/" + tinyIcon);
656       result.put("icon_alt", iconAlt);
657
658       return result;
659     }
660   }
661
662   protected class ContentCommentCountField implements EntityAdapterDefinition.CalculatedField {
663     private String extraCondition;
664
665     public ContentCommentCountField(String anExtraCondition) {
666       super();
667
668       extraCondition = anExtraCondition;
669     }
670
671     public Object getValue(EntityAdapter anEntityAdapter) {
672       try {
673         return Integer.toString(
674             DatabaseComment.getInstance().getSize(
675                   "to_media="+anEntityAdapter.get("id")+" " + extraCondition));
676       }
677       catch (Throwable t) {
678         throw new RuntimeException(t.getMessage());
679       }
680     }
681   }
682
683   protected class HumanReadableSizeField implements EntityAdapterDefinition.CalculatedField {
684       private String fieldName;
685
686       public HumanReadableSizeField(String aFieldName) {
687         fieldName= aFieldName;
688       }
689
690       public Object getValue(EntityAdapter anEntityAdapter) {
691         try {
692           String size = (String) anEntityAdapter.get(fieldName);
693           if (size!=null)
694             return NumberUtils.humanReadableSize(Double.parseDouble(size));
695                                         return "";
696         }
697         catch (Throwable t) {
698           throw new RuntimeException(t.getMessage());
699         }
700       }
701     }
702
703
704   protected class ContentMediaCountField implements EntityAdapterDefinition.CalculatedField {
705     private String table;
706     private boolean published;
707
708     public ContentMediaCountField(String aTable, boolean anOnlyPublished) {
709       table = aTable;
710       published = anOnlyPublished;
711     }
712
713     public ContentMediaCountField(String aTable) {
714       this(aTable, true);
715     }
716
717     public Object getValue(EntityAdapter anEntityAdapter) {
718       try {
719         ArrayList extraTable = new ArrayList();
720         extraTable.add(table+" m");
721         String selectSql = "cxm.media_id=m.id and cxm.content_id="+
722           anEntityAdapter.get("id");
723         if (published)
724           selectSql+= " and m.is_published='t'";
725
726         return Integer.toString(
727             DatabaseContentToMedia.getInstance().getSize(
728               "cxm", extraTable, selectSql));
729       }
730       catch (Throwable t) {
731         throw new RuntimeException(t.getMessage());
732       }
733     }
734   }
735
736   protected class ContentToIsLockedField implements EntityAdapterDefinition.CalculatedField {
737     private ModuleContent contentModule;
738
739     public ContentToIsLockedField() {
740       contentModule = new ModuleContent();
741     }
742
743     public Object getValue(EntityAdapter anEntityAdapter) {
744       try {
745         return new Boolean(contentModule.queryArticleLock(anEntityAdapter.getEntity().getId())!=null);
746       }
747       catch (Throwable t) {
748         throw new RuntimeException(t.getMessage());
749       }
750     }
751   }
752     protected class ContentIsOriginalField implements EntityAdapterDefinition.CalculatedField {
753     public Object getValue(EntityAdapter anEntityAdapter) throws MirLocalizerFailure {
754       try {
755
756         //ML: add check on article type
757         boolean result = (anEntityAdapter.get("parent")==null);
758
759         return new Boolean(result);
760       }
761       catch (Throwable t) {
762         throw new MirLocalizerFailure(t);
763       }
764     }
765   }
766
767   protected class ContentToOriginalField implements EntityAdapterDefinition.CalculatedField {
768     public Object getValue(EntityAdapter anEntityAdapter) throws MirLocalizerFailure {
769       try {
770         if (anEntityAdapter.get("parent")!=null)
771           return anEntityAdapter.get("parent");
772                                 return anEntityAdapter;
773       }
774       catch (Throwable t) {
775         throw new MirLocalizerFailure(t);
776       }
777     }
778   }
779
780   protected class ContentToTranslationsField implements EntityAdapterDefinition.CalculatedField {
781     public Object getValue(EntityAdapter anEntityAdapter) {
782       try {
783         return anEntityAdapter.getRelation(
784                     "is_published='t' and to_content="+anEntityAdapter.get("id"),
785                     "id",
786                     "content" );
787       }
788       catch (Throwable t) {
789         throw new RuntimeException(t.getMessage());
790       }
791     }
792   }
793
794   protected class ContentToLanguageNameField implements EntityAdapterDefinition.CalculatedField {
795     public Object getValue(EntityAdapter anEntityAdapter) throws MirLocalizerFailure {
796       try {
797         String result = "";
798         EntityAdapter language = (EntityAdapter) anEntityAdapter.get("language");
799         if (language != null) {
800           if (language.get("code").equals("ot")) {
801             result = ((String) anEntityAdapter.get("subtitle")).trim();
802             if (result == null || result.equals(""))
803               result = (String) language.get("name");
804           } else {
805             result = (String) language.get("name");
806           }
807         }
808
809         return result;
810       }
811       catch (Throwable t) {
812         throw new MirLocalizerFailure(t);
813       }
814     }
815   }
816
817   protected class ContentToTranslationFunction implements Generator.Function {
818     private EntityAdapter target;
819     private String targetId;
820     private String targetLanguageId;
821
822     public ContentToTranslationFunction(EntityAdapter aTarget) {
823       target = aTarget;
824       targetId = (String) target.get("id");
825       targetLanguageId = (String) target.get("to_language");
826     }
827
828     public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
829       if (aParameters.size()!=1 || !(aParameters.get(0) instanceof String))
830         throw new GeneratorExc("1 string parameter expected");
831
832       try {
833         String language = (String) aParameters.get(0);
834         String languageId = languageModule.languageIdForCode(language);
835         Object result = null;
836
837         if (languageId != null && !targetLanguageId.equals(languageId)) {
838           result = target.getToOneRelation(
839               "is_published='t' and to_content=" + targetId + " and to_language='" + JDBCStringRoutines.escapeStringLiteral(languageId) + "'",
840               "id", "content");
841         }
842
843         if (result == null)
844           result = target;
845
846         return result;
847       }
848       catch (Throwable t) {
849         t.printStackTrace(System.out);
850         throw new GeneratorFailure(t);
851       }
852     }
853   }
854
855   protected class ContentToTranslationField implements EntityAdapterDefinition.CalculatedField {
856     public Object getValue(EntityAdapter anEntityAdapter) throws MirLocalizerFailure {
857       try {
858         return new ContentToTranslationFunction((EntityAdapter) anEntityAdapter.get("to_original"));
859       }
860       catch (Throwable t) {
861         throw new MirLocalizerFailure(t);
862       }
863     }
864   }
865 }
866