View Javadoc

1   package org.gnomekr.potron.service;
2   
3   import java.io.IOException;
4   import java.io.PrintWriter;
5   import java.io.Reader;
6   import java.io.Writer;
7   import java.util.ArrayList;
8   import java.util.Date;
9   import java.util.HashMap;
10  import java.util.List;
11  import java.util.Map;
12  
13  import org.apache.commons.lang.NullArgumentException;
14  import org.apache.commons.lang.StringUtils;
15  import org.apache.commons.logging.Log;
16  import org.apache.commons.logging.LogFactory;
17  import org.gnomekr.potron.data.Entry;
18  import org.gnomekr.potron.data.EntryLog;
19  import org.gnomekr.potron.data.Header;
20  import org.gnomekr.potron.data.Lock;
21  import org.gnomekr.potron.data.PluralForms;
22  import org.gnomekr.potron.data.Template;
23  import org.gnomekr.potron.data.TranslatedEntry;
24  import org.gnomekr.potron.data.Translation;
25  import org.gnomekr.potron.data.User;
26  import org.gnomekr.potron.parser.IPOParserCallback;
27  import org.gnomekr.potron.parser.POParser;
28  import org.gnomekr.potron.parser.ParseException;
29  import org.gnomekr.potron.parser.ParserEntry;
30  import org.hibernate.Criteria;
31  import org.hibernate.Session;
32  import org.hibernate.criterion.Expression;
33  import org.springframework.orm.hibernate3.SessionFactoryUtils;
34  
35  /***
36   * TranslationManager.java
37   * @author iolo
38   * @version $Revision: 1.19 $ $Date: 2005/09/11 05:49:44 $
39   */
40  public class TranslationManager extends BasePotronService implements
41          ITranslationManager {
42  
43      private static Log log = LogFactory.getLog(TranslationManager.class);
44  
45      /***
46       * @see org.gnomekr.potron.service.ITranslationManager#addTranslation(org.gnomekr.potron.data.Translation)
47       */
48      public long addTranslation(Translation translation) {
49          if (translation == null) {
50              throw new NullArgumentException("translation");
51          }
52  
53          if (log.isDebugEnabled()) {
54              log.debug("Adding new translation.");
55          }
56  
57          final Session session = getHibernateSession();
58  
59          translation.setRegisteredDate(new Date());
60          translation.setRevisionDate(new Date());
61  
62          Template template = translation.getTemplate();
63  
64          List<TranslatedEntry> entries = translation.getEntries();
65          if (entries == null) {
66              entries = new ArrayList<TranslatedEntry>();
67          }
68  
69          for (Entry entry : template.getEntries()) {
70              entries.add(new TranslatedEntry(entry, translation));
71          }
72  
73          translation.setEntries(entries);
74  
75          template.getTranslations().add(translation);
76  
77          long id = (Long) session.save(translation);
78  
79          if (log.isInfoEnabled()) {
80              log.info("Translation has been registered successfully : ");
81              log.debug(" - translation : " + translation);
82          }
83  
84          return id;
85      }
86  
87      /***
88       * @see org.gnomekr.potron.service.ITranslationManager#addTranslation(org.gnomekr.potron.data.Translation, java.io.Reader)
89       */
90      public long addTranslation(final Translation translation, Reader reader)
91              throws ParseException, IOException {
92          if (translation == null) {
93              throw new NullArgumentException("translation");
94          }
95  
96          if (reader == null) {
97              throw new NullArgumentException("reader");
98          }
99  
100         if (log.isDebugEnabled()) {
101             log.debug("Importing existing translation file.");
102         }
103 
104         final Session session = getHibernateSession();
105 
106         translation.setRegisteredDate(new Date());
107         translation.setRevisionDate(new Date());
108 
109         Template template = translation.getTemplate();
110 
111         final Map<String, Entry> entryMap = new HashMap<String, Entry>();
112         final List<TranslatedEntry> entries = new ArrayList<TranslatedEntry>();
113         final List<Header> headers = new ArrayList<Header>();
114 
115         for (Entry entry : template.getEntries()) {
116             entryMap.put(entry.getKey(), entry);
117         }
118 
119         final User translator = getContextUser();
120 
121         IPOParserCallback callback = new IPOParserCallback() {
122 
123             public void startDocument() {
124             }
125 
126             public void onComment(String comment) {
127                 translation.setComment(comment);
128             }
129 
130             public void onHeader(String key, String value) {
131                 headers.add(new Header(key, value));
132             }
133 
134             public void onHeaderPluralForm(int nplural, String expression) {
135                 translation
136                         .setPluralForms(new PluralForms(nplural, expression));
137             }
138 
139             public void onEntry(ParserEntry entry) {
140                 Entry e = entryMap.get(entry.getMsgId());
141                 if (e == null) {
142                     if (log.isWarnEnabled()) {
143                         log.warn("Obsolete entry has been found :");
144                         log.warn("  - msgid : " + entry.getMsgId());
145                         log.warn("  - msgstr : " + entry.getMsgStr());
146                     }
147                 } else {
148                     TranslatedEntry t = new TranslatedEntry(entry);
149 
150                     t.setEntry(e);
151                     t.setTranslation(translation);
152                     t.setModifiedDate(new Date());
153                     t.setTranslator(translator);
154 
155                     entries.add(t);
156                 }
157             }
158 
159             public void endDocument() {
160             }
161         };
162 
163         POParser parser = new POParser(callback);
164         parser.parse(reader);
165 
166         translation.setHeaders(headers);
167         translation.setEntries(entries);
168 
169         template.getTranslations().add(translation);
170 
171         long id = (Long) session.save(translation);
172 
173         if (log.isInfoEnabled()) {
174             log.info("Translation has been registered successfully : ");
175             log.debug(" - translation : " + translation);
176         }
177 
178         return id;
179     }
180 
181     /***
182      * @see org.gnomekr.potron.service.ITranslationManager#exportTranslation(long, java.io.Writer)
183      */
184     @SuppressWarnings("unchecked")
185     public void exportTranslation(long id, Writer writer) throws IOException {
186         final PrintWriter out = (writer instanceof PrintWriter) ? (PrintWriter) writer
187                 : new PrintWriter(writer);
188 
189         final Translation trans = getTranslation(id);
190         // emit global comments
191         out.println(trans.getComment());
192 
193         // emit global headers
194         final List<Header> headers = trans.getHeaders();
195         for (Header header : headers) {
196             out.println("\"" + header.getName() + ": " + header.getValue()
197                     + "//n\"");
198             // TODO: fill header values for user and language team
199         }
200         out.println();
201 
202         // emit entries
203         final List<TranslatedEntry> entries = getTranslatedEntries(id);
204         for (TranslatedEntry entry : entries) {
205             // emit entry comment
206             out.println("#: " + entry.getEntry().getOccurrences());
207             if (entry.isFuzzy()) {
208                 out.println("#, fuzzy");
209             }
210             out.println(entry.getComment());
211             // emit entry msgid
212             out.println("msgid \"" + entry.getEntry().getKey() + "\"");
213             // emit entry msgstr
214             out.println("msgstr \"" + entry.getTranslatedString() + "\"");
215             // TODO: handle plurals here
216             out.println();
217         }
218         out.flush();
219         out.close();
220     }
221 
222     /***
223      * @see org.gnomekr.potron.service.ITranslationManager#getTranslation(long)
224      */
225     public Translation getTranslation(long id) {
226         if (log.isDebugEnabled()) {
227             log.debug("Loading translation info : " + id);
228         }
229 
230         final Session session = getHibernateSession();
231 
232         Translation translation = (Translation) session.get(
233                 Translation.class,
234                 id);
235 
236         if (log.isTraceEnabled()) {
237             log.trace("Retreived translation info : ");
238             log.trace(translation);
239         }
240 
241         return translation;
242     }
243 
244     /***
245      * @see org.gnomekr.potron.service.ITranslationManager#updateTranslation(org.gnomekr.potron.data.Translation)
246      */
247     public void updateTranslation(Translation translation) {
248         if (translation == null) {
249             throw new NullArgumentException("translation");
250         }
251 
252         if (log.isDebugEnabled()) {
253             log.debug("Updating translation information : "
254                     + translation.getName());
255         }
256 
257         Session session = SessionFactoryUtils.getSession(
258                 getSessionFactory(),
259                 false);
260 
261         translation.setRevisionDate(new Date());
262 
263         session.merge(translation);
264 
265         if (log.isInfoEnabled()) {
266             log
267                     .info("Translation information has been updated successfully : ");
268             log.debug(translation);
269         }
270     }
271 
272     /***
273      * @see org.gnomekr.potron.service.ITranslationManager#updateTranslation(org.gnomekr.potron.data.Translation, java.io.Reader)
274      */
275     public void updateTranslation(Translation translation, Reader reader)
276             throws ParseException, IOException {
277         if (translation == null) {
278             throw new NullArgumentException("translation");
279         }
280 
281         if (reader == null) {
282             throw new NullArgumentException("reader");
283         }
284 
285         if (log.isDebugEnabled()) {
286             log.debug("Updating translation information : "
287                     + translation.getName());
288         }
289 
290         updateTranslation(translation);
291 
292         final Translation oldTranslation = getTranslation(translation.getId());
293 
294         Template template = translation.getTemplate();
295 
296         final Map<String, Entry> entryMap = new HashMap<String, Entry>();
297         final List<Header> headers = new ArrayList<Header>();
298 
299         for (Entry entry : template.getEntries()) {
300             if (entry != null) {
301                 entryMap.put(entry.getKey(), entry);
302             }
303         }
304 
305         final Map<String, TranslatedEntry> oldTranslations = new HashMap<String, TranslatedEntry>();
306         for (TranslatedEntry entry : oldTranslation.getEntries()) {
307             oldTranslations.put(entry.getEntry().getKey(), entry);
308         }
309 
310         final Session session = SessionFactoryUtils.getSession(
311                 getSessionFactory(),
312                 false);
313 
314         final User translator = getContextUser();
315 
316         IPOParserCallback callback = new IPOParserCallback() {
317 
318             public void startDocument() {
319             }
320 
321             public void onComment(String comment) {
322                 oldTranslation.setComment(comment);
323             }
324 
325             public void onHeader(String key, String value) {
326                 headers.add(new Header(key, value));
327             }
328 
329             public void onHeaderPluralForm(int nplural, String expression) {
330                 oldTranslation.setPluralForms(new PluralForms(nplural,
331                         expression));
332             }
333 
334             public void onEntry(ParserEntry entry) {
335                 Entry e = entryMap.get(entry.getMsgId());
336                 if (e == null) {
337                     if (log.isWarnEnabled()) {
338                         log.warn("Obsolete entry has been found :");
339                         log.warn("  - msgid : " + entry.getMsgId());
340                         log.warn("  - msgstr : " + entry.getMsgStr());
341                     }
342                 } else {
343                     TranslatedEntry t = new TranslatedEntry(entry);
344 
345                     if (oldTranslations.containsKey(e.getKey())) {
346                         TranslatedEntry oldEntry = oldTranslations.get(e
347                                 .getKey());
348 
349                         oldEntry.setModifiedDate(new Date());
350                         oldEntry.setPluralStrings(t.getPluralStrings());
351                         oldEntry.setTranslatedString(t.getTranslatedString());
352                         oldEntry.setModifiedDate(new Date());
353                     } else {
354                         t.setEntry(e);
355                         t.setTranslation(oldTranslation);
356                         t.setTranslator(translator);
357                         t.setModifiedDate(new Date());
358 
359                         oldTranslation.getEntries().add(t);
360                     }
361                 }
362             }
363 
364             public void endDocument() {
365             }
366         };
367 
368         POParser parser = new POParser(callback);
369         parser.parse(reader);
370 
371         oldTranslation.getHeaders().clear();
372         oldTranslation.getHeaders().addAll(headers);
373 
374         oldTranslation.setRevisionDate(new Date());
375 
376         session.update(oldTranslation);
377 
378         if (log.isInfoEnabled()) {
379             log
380                     .info("Translation information has been updated successfully : ");
381             log.debug(oldTranslation);
382         }
383     }
384 
385     public void removeTranslation(long id) {
386         if (log.isDebugEnabled()) {
387             log.debug("Deleting translation : " + id);
388         }
389 
390         final Session session = getHibernateSession();
391 
392         Translation translation = getTranslation(id);
393 
394         session.delete(translation);
395 
396         if (log.isInfoEnabled()) {
397             log.info("Translation has been deleted successfully : ");
398             log.info(" - translation : " + translation);
399         }
400     }
401 
402     /***
403      * @see org.gnomekr.potron.service.ITranslationManager#getTranslatedEntries(long)
404      */
405     @SuppressWarnings("unchecked")
406     public List<TranslatedEntry> getTranslatedEntries(long translationId) {
407         if (log.isDebugEnabled()) {
408             log.debug("Retrieving all translated entries : " + translationId);
409         }
410 
411         final Session session = getHibernateSession();
412 
413         Criteria criteria = session.createCriteria(TranslatedEntry.class);
414         criteria.add(Expression.isNotNull("translatedString"));
415         criteria.add(Expression.isNull("lock.owner"));
416         criteria.add(Expression.eq("translation.id", translationId));
417 
418         return criteria.list();
419     }
420 
421     /***
422      * @see org.gnomekr.potron.service.ITranslationManager#getUntranslatedEntries(long, boolean)
423      */
424     @SuppressWarnings("unchecked")
425     public List<TranslatedEntry> getUntranslatedEntries(
426             long translationId,
427             boolean includeCheckedOutEntries) {
428         if (log.isDebugEnabled()) {
429             log.debug("Retrieving all untranslated entries : " + translationId);
430         }
431 
432         final Session session = getHibernateSession();
433 
434         Criteria criteria = session.createCriteria(TranslatedEntry.class);
435         criteria.add(Expression.isNull("translatedString"));
436         criteria.add(Expression.eq("translation.id", translationId));
437 
438         if (!includeCheckedOutEntries) {
439             criteria.add(Expression.isNull(("lock.owner")));
440         }
441 
442         return criteria.list();
443     }
444 
445     /***
446      * @see org.gnomekr.potron.service.ITranslationManager#getFuzzyEntries(long, boolean)
447      */
448     @SuppressWarnings("unchecked")
449     public List<TranslatedEntry> getFuzzyEntries(
450             long translationId,
451             boolean includeCheckedOutEntries) {
452         if (log.isDebugEnabled()) {
453             log.debug("Retrieving all fuzzy entries : " + translationId);
454         }
455 
456         final Session session = getHibernateSession();
457 
458         Criteria criteria = session.createCriteria(TranslatedEntry.class);
459         criteria.add(Expression.eq("fuzzy", true));
460         criteria.add(Expression.eq("translation.id", translationId));
461 
462         if (!includeCheckedOutEntries) {
463             criteria.add(Expression.isNull("lock"));
464         }
465 
466         return criteria.list();
467     }
468 
469     /***
470      * @see org.gnomekr.potron.service.ITranslationManager#getEntry(long)
471      */
472     public TranslatedEntry getEntry(long id) {
473         final Session session = getHibernateSession();
474 
475         TranslatedEntry entry = (TranslatedEntry) session.load(
476                 TranslatedEntry.class,
477                 id);
478 
479         return entry;
480     }
481 
482     /***
483      * @see org.gnomekr.potron.service.ITranslationManager#getCheckedOutEntries(long)
484      */
485     @SuppressWarnings("unchecked")
486     public List<TranslatedEntry> getCheckedOutEntries(long translationId) {
487         if (log.isDebugEnabled()) {
488             log.debug("Retrieving all checked out entries : " + translationId);
489         }
490 
491         final Session session = getHibernateSession();
492 
493         Criteria criteria = session.createCriteria(TranslatedEntry.class);
494         criteria.add(Expression.eq("translation.id", translationId));
495         criteria.add(Expression.isNotNull("lock.owner.userName"));
496 
497         return criteria.list();
498     }
499 
500     /***
501      * @see org.gnomekr.potron.service.ITranslationManager#getCheckedOutEntries(java.lang.String)
502      */
503     @SuppressWarnings("unchecked")
504     public List<TranslatedEntry> getCheckedOutEntries(String userName) {
505         if (log.isDebugEnabled()) {
506             log.debug("Retrieving all checked out entries for user : "
507                     + userName);
508         }
509 
510         final Session session = getHibernateSession();
511 
512         Criteria criteria = session.createCriteria(TranslatedEntry.class);
513         criteria.add(Expression.eq("lock.owner.userName", userName));
514 
515         return criteria.list();
516     }
517 
518     /***
519      * @see org.gnomekr.potron.service.ITranslationManager#checkOutEntry(long)
520      */
521     public TranslatedEntry checkOutEntry(long entryId)
522             throws AlreadyCheckedOutException {
523         if (log.isDebugEnabled()) {
524             log.debug("Checking out entry : " + entryId);
525         }
526 
527         final Session session = getHibernateSession();
528 
529         TranslatedEntry entry = (TranslatedEntry) session.load(
530                 TranslatedEntry.class,
531                 entryId);
532 
533         User user = getContextUser();
534         Lock lock = entry.getLock();
535 
536         if (lock != null) {
537             throw new AlreadyCheckedOutException(user.getUserName());
538         }
539 
540         lock = new Lock();
541         lock.setOwner(user);
542         lock.setCreatedDate(new Date());
543 
544         entry.setLock(lock);
545 
546         session.merge(entry);
547 
548         return entry;
549     }
550 
551     /***
552      * @see org.gnomekr.potron.service.ITranslationManager#abandonCheckedOutEntry(long)
553      */
554     public void abandonCheckedOutEntry(long entryId) {
555         if (log.isDebugEnabled()) {
556             log.debug("Abandon checked out entry : " + entryId);
557         }
558 
559         final Session session = getHibernateSession();
560 
561         TranslatedEntry entry = (TranslatedEntry) session.load(
562                 TranslatedEntry.class,
563                 entryId);
564 
565         User user = getContextUser();
566         Lock lock = entry.getLock();
567         if (lock != null) {
568             if (!lock.getOwner().equals(user)) {
569                 if (log.isWarnEnabled()) {
570                     log.warn("The caller does not own the lock on this entry.");
571                     log.warn(" - caller : " + user);
572                     log.warn(" - owner : " + lock.getOwner());
573                 }
574                 //TODO Throw security exception. 
575                 return;
576             }
577 
578             entry.setLock(null);
579             session.update(entry);
580         }
581     }
582 
583     /***
584      * @see org.gnomekr.potron.service.ITranslationManager#checkInEntry(long, java.lang.String, boolean)
585      */
586     public void checkInEntry(
587             long entryId,
588             String translatedString,
589             boolean fuzzy) {
590         checkInEntry(entryId, translatedString, null, fuzzy);
591     }
592 
593     /***
594      * @see org.gnomekr.potron.service.ITranslationManager#checkInEntry(long, java.lang.String, java.util.List, boolean)
595      */
596     public void checkInEntry(
597             long entryId,
598             String translatedString,
599             List<String> pluralStrings,
600             boolean fuzzy) {
601         if (log.isDebugEnabled()) {
602             log.debug("Checking in entry : " + entryId);
603         }
604 
605         final Session session = getHibernateSession();
606 
607         TranslatedEntry entry = (TranslatedEntry) session.load(
608                 TranslatedEntry.class,
609                 entryId);
610 
611         if (StringUtils.isNotEmpty(entry.getEntry().getPluralKey())) {
612             int nplural = entry.getTranslation().getPluralForms().getCount();
613             if (pluralStrings == null || pluralStrings.size() != nplural - 1) {
614                 String msg = "Not enough plural string messages for entry. Requires "
615                         + (nplural - 1);
616                 throw new IllegalArgumentException(msg);
617             }
618 
619             entry.setPluralStrings(new ArrayList<String>(pluralStrings));
620         }
621 
622         User user = getContextUser();
623 
624         Lock lock = entry.getLock();
625         if (lock == null) {
626             if (log.isWarnEnabled()) {
627                 log.warn("Only locked entries can be checked in.");
628             }
629         } else {
630             if (!lock.getOwner().equals(user)) {
631                 if (log.isWarnEnabled()) {
632                     log.warn("The caller does not own the lock on this entry.");
633                     log.warn(" - caller : " + user);
634                     log.warn(" - owner : " + lock.getOwner());
635                 }
636                 //TODO Throw security exception. 
637                 return;
638             }
639 
640             if (entry.getTranslatedString() != null
641                     && entry.getModifiedDate() != null) {
642                 EntryLog entryLog = new EntryLog(entry);
643                 entry.getEntryLogs().add(entryLog);
644             }
645 
646             entry.setFuzzy(fuzzy);
647             entry.setTranslator(user);
648             entry.setTranslatedString(translatedString);
649             entry.setModifiedDate(new Date());
650             entry.setLock(null);
651 
652             session.merge(entry);
653         }
654     }
655 }