1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.mail.internal.factory.template

File DefaultMailTemplateManager.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

16
47
7
1
207
140
22
0.47
6.71
7
3.14

Classes

Class Line # Actions
DefaultMailTemplateManager 56 47 0% 22 3
0.9571428395.7%
 

Contributing tests

This file is covered by 6 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.mail.internal.factory.template;
21   
22    import java.io.StringWriter;
23    import java.util.Locale;
24    import java.util.Map;
25   
26    import javax.inject.Inject;
27    import javax.inject.Named;
28    import javax.inject.Provider;
29    import javax.inject.Singleton;
30    import javax.mail.MessagingException;
31   
32    import org.apache.velocity.VelocityContext;
33    import org.xwiki.bridge.DocumentAccessBridge;
34    import org.xwiki.component.annotation.Component;
35    import org.xwiki.localization.LocaleUtils;
36    import org.xwiki.model.EntityType;
37    import org.xwiki.model.reference.DocumentReference;
38    import org.xwiki.model.reference.DocumentReferenceResolver;
39    import org.xwiki.model.reference.EntityReference;
40    import org.xwiki.model.reference.EntityReferenceSerializer;
41    import org.xwiki.velocity.VelocityManager;
42    import org.xwiki.velocity.XWikiVelocityException;
43   
44    import com.xpn.xwiki.XWikiContext;
45    import com.xpn.xwiki.XWikiException;
46   
47    /**
48    * Default implementation evaluating template properties by taking them from {@code XWiki.Mail} and applying Velocity on
49    * them.
50    *
51    * @version $Id: 7f0b2be0ccec3c9bf2188602965775fa9fcecd1c $
52    * @since 6.1RC1
53    */
54    @Component
55    @Singleton
 
56    public class DefaultMailTemplateManager implements MailTemplateManager
57    {
58    private static final EntityReference MAIL_CLASS =
59    new EntityReference("Mail", EntityType.DOCUMENT, new EntityReference("XWiki", EntityType.SPACE));
60   
61    private static final String LANGUAGE_PROPERTY_NAME = "language";
62   
63    @Inject
64    private DocumentAccessBridge documentBridge;
65   
66    @Inject
67    private EntityReferenceSerializer<String> serializer;
68   
69    @Inject
70    @Named("current")
71    private DocumentReferenceResolver<EntityReference> resolver;
72   
73    @Inject
74    private VelocityManager velocityManager;
75   
76    @Inject
77    private Provider<XWikiContext> xwikiContextProvider;
78   
 
79  24 toggle @Override
80    public String evaluate(DocumentReference templateReference, String property, Map<String, Object> velocityVariables,
81    Object localeValue) throws MessagingException
82    {
83  24 Locale locale = getLocale(localeValue);
84   
85    // Note: Make sure to use the class reference relative to the template's wiki and not the current wiki.
86  24 DocumentReference mailClassReference = this.resolver.resolve(MAIL_CLASS, templateReference.getWikiReference());
87   
88  24 VelocityContext velocityContext = createVelocityContext(velocityVariables);
89   
90  24 String templateFullName = this.serializer.serialize(templateReference);
91   
92  24 int objectNumber = getObjectMailNumber(templateReference, mailClassReference, locale);
93   
94  23 String content =
95    this.documentBridge.getProperty(templateReference, mailClassReference, objectNumber, property).toString();
96  23 try {
97  23 StringWriter writer = new StringWriter();
98  23 velocityManager.getVelocityEngine().evaluate(velocityContext, writer, templateFullName, content);
99  22 return writer.toString();
100    } catch (XWikiVelocityException e) {
101  1 throw new MessagingException(String.format(
102    "Failed to evaluate property [%s] for Document [%s] and locale [%s]",
103    property, templateReference, localeValue), e);
104    }
105    }
106   
 
107  2 toggle @Override
108    public String evaluate(DocumentReference templateReference, String property, Map<String, Object> data)
109    throws MessagingException
110    {
111  2 return evaluate(templateReference, property, data, null);
112    }
113   
114    /**
115    * @return the number of the XWiki.Mail xobject with language xproperty is equal to the language parameter if not
116    * exist return the XWiki.Mail xobject with language xproperty as default language if not exist return the first
117    * XWiki.Mail xobject if there is only one XWiki.Mail xobject
118    */
 
119  24 toggle private int getObjectMailNumber(DocumentReference templateReference, DocumentReference mailClassReference,
120    Locale language) throws MessagingException
121    {
122  24 int number = this.documentBridge.getObjectNumber(templateReference, mailClassReference, LANGUAGE_PROPERTY_NAME,
123    language.getLanguage());
124   
125  24 int mailObjectsCount = getMailObjectsCount(templateReference, mailClassReference);
126   
127    // Check that the language passed is not the default language
128  24 if (!getDefaultLocale().equals(language) && number == -1) {
129  3 number = this.documentBridge.getObjectNumber(templateReference, mailClassReference, LANGUAGE_PROPERTY_NAME,
130    getDefaultLocale().getLanguage());
131    }
132   
133  24 if (mailObjectsCount == 1 && number == -1) {
134  1 number = 0;
135  23 } else if (mailObjectsCount == 0 && number == -1) {
136  0 throw new MessagingException(String.format(
137    "No [%s] object found in the Document [%s] for language [%s]", MAIL_CLASS.toString(),
138    templateReference, language));
139  23 } else if (number == -1) {
140  1 throw new MessagingException(String.format(
141    "No [%s] object matches the locale [%s] or the default locale [%s] in the Document [%s]",
142    MAIL_CLASS.toString(), language, getDefaultLocale(), templateReference));
143    }
144  23 return number;
145    }
146   
 
147  24 toggle private int getMailObjectsCount(DocumentReference templateReference, DocumentReference mailClassReference)
148    throws MessagingException
149    {
150  24 XWikiContext context = this.xwikiContextProvider.get();
151  24 int objectsCount;
152  24 try {
153  24 objectsCount = context.getWiki().getDocument(templateReference, context).getXObjects(mailClassReference)
154    .size();
155    } catch (XWikiException e) {
156  0 throw new MessagingException(String.format(
157    "Failed to find number of [%s] objects in Document [%s]", mailClassReference, templateReference), e);
158    }
159  24 return objectsCount;
160    }
161   
 
162  24 toggle private VelocityContext createVelocityContext(Map<String, Object> velocityVariables)
163    {
164    // Note: We create an inner Velocity Context to make it read only and try to prevent the script to modify
165    // its bindings. VelocityContext protect the inner VelocitContext but value could be modified directly
166    // (when value are mutable, like Map or List for example).
167    // However, this whole code is executed in a thread and we recreate the context for each email so it should be
168    // pretty safe!
169  24 VelocityContext existingVelocityContext = this.velocityManager.getVelocityContext();
170  24 VelocityContext velocityContext;
171  24 if (existingVelocityContext != null) {
172  18 velocityContext = new VelocityContext(existingVelocityContext);
173    } else {
174  6 velocityContext = new VelocityContext();
175    }
176  24 if (velocityVariables != null) {
177  21 for (Map.Entry<String, Object> velocityVariable : velocityVariables.entrySet()) {
178  48 velocityContext.put(velocityVariable.getKey(), velocityVariable.getValue());
179    }
180    }
181  24 return velocityContext;
182    }
183   
 
184  30 toggle private Locale getDefaultLocale()
185    {
186  30 XWikiContext context = this.xwikiContextProvider.get();
187  30 return context.getWiki().getDefaultLocale(context);
188    }
189   
 
190  24 toggle private Locale getLocale(Object languageValue)
191    {
192  24 Locale locale;
193   
194  24 if ((languageValue == null) || ((languageValue instanceof Locale) && Locale.ROOT.equals(languageValue))) {
195  2 locale = getDefaultLocale();
196    } else {
197    // Note: we support both a Locale type and String mostly for backward-compatibility reasons (the first
198    // version of this API only supported String and we've moved to support Locale).
199  22 if (languageValue instanceof Locale) {
200  7 locale = (Locale) languageValue;
201    } else {
202  15 locale = LocaleUtils.toLocale(languageValue.toString());
203    }
204    }
205  24 return locale;
206    }
207    }