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
191 out.println(trans.getComment());
192
193
194 final List<Header> headers = trans.getHeaders();
195 for (Header header : headers) {
196 out.println("\"" + header.getName() + ": " + header.getValue()
197 + "//n\"");
198
199 }
200 out.println();
201
202
203 final List<TranslatedEntry> entries = getTranslatedEntries(id);
204 for (TranslatedEntry entry : entries) {
205
206 out.println("#: " + entry.getEntry().getOccurrences());
207 if (entry.isFuzzy()) {
208 out.println("#, fuzzy");
209 }
210 out.println(entry.getComment());
211
212 out.println("msgid \"" + entry.getEntry().getKey() + "\"");
213
214 out.println("msgstr \"" + entry.getTranslatedString() + "\"");
215
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
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
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 }