/** * Axelor Business Solutions * * Copyright (C) 2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.axelor.tool.template; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Date; import java.util.Locale; import java.util.Map; import org.joda.time.LocalDate; import org.joda.time.LocalDateTime; import org.joda.time.LocalTime; import org.stringtemplate.v4.AttributeRenderer; import org.stringtemplate.v4.DateRenderer; import org.stringtemplate.v4.Interpreter; import org.stringtemplate.v4.ModelAdaptor; import org.stringtemplate.v4.NumberRenderer; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.StringRenderer; import org.stringtemplate.v4.misc.ObjectModelAdaptor; import com.axelor.apps.tool.exception.IExceptionMessage; import com.axelor.auth.AuthUtils; import com.axelor.db.Model; import com.axelor.db.mapper.Mapper; import com.axelor.db.mapper.Property; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; import com.axelor.meta.db.MetaSelectItem; import com.axelor.meta.db.repo.MetaSelectItemRepository; import com.axelor.rpc.Resource; import com.beust.jcommander.internal.Maps; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.io.Files; public class TemplateMaker { private Map<String, Object> context; private Map<String, Object> localContext; private String template; private STGroup stGroup; private Locale locale; public TemplateMaker(Locale locale, char delimiterStartChar, char delimiterStopChar) { this.locale = locale; this.stGroup = new STGroup(delimiterStartChar,delimiterStopChar); //Custom renderer this.stGroup.registerModelAdaptor(Model.class, new ModelFormatRenderer()); this.stGroup.registerRenderer(LocalDate.class, new LocalDateRenderer()); this.stGroup.registerRenderer(LocalDateTime.class, new LocalDateTimeRenderer()); this.stGroup.registerRenderer(LocalTime.class, new LocalTimeRenderer()); //Default renderer provide by ST this.stGroup.registerRenderer(String.class, new StringRenderer()); this.stGroup.registerRenderer(Number.class, new NumberRenderer()); this.stGroup.registerRenderer(Date.class, new DateRenderer()); } public void setContext(Model model) { this.setContext(model, null, null); } public void setContext(Model model, String nameInContext) { this.setContext(model, null, nameInContext); } public void setContext(Model model, Map<String, Object> map) { this.setContext(model, map, null); } public void setContext(Model model, Map<String, Object> map, String nameInContext) { Preconditions.checkNotNull(model); this.context = makeContext(nameInContext, model, map); } private Map<String, Object> makeContext(String nameInContext, Model model, Map<String, Object> map) { Map<String, Object> _map = Maps.newHashMap(); if(nameInContext != null) { _map.put(nameInContext, model); } else { _map.putAll(Resource.toMap(model)); } if(map != null) { _map.putAll(map); } return _map; } public void setTemplate(String text) { this.template = text; } public void setTemplate(File file) throws FileNotFoundException { if (!file.isFile()) { throw new FileNotFoundException(I18n.get(IExceptionMessage.TEMPLATE_MAKER_1)+": " + file.getName()); } String text; try { text = Files.toString(file, Charsets.UTF_8); } catch (IOException e) { throw new IllegalArgumentException(e); } this.setTemplate(text); } public void addInContext(String key, Object value) { if(localContext == null) { localContext = Maps.newHashMap(); } localContext.put(key, value); } public void addInContext(Map<String, Object> map) { if(localContext == null) { localContext = Maps.newHashMap(); } localContext.putAll(map); } public Class<?> getBeanClass(Model model) { return model.getClass(); } public String make() { if (Strings.isNullOrEmpty(this.template)) { throw new IllegalArgumentException(I18n.get(IExceptionMessage.TEMPLATE_MAKER_2)); } ST st = new ST(stGroup, template); Map<String, Object> _map = Maps.newHashMap(); if(localContext != null && !localContext.isEmpty()) { _map.putAll(localContext); } _map.putAll(context); //Internal context _map.put("__user__", AuthUtils.getUser()); _map.put("__date__", new LocalDate()); _map.put("__time__", new LocalTime()); _map.put("__datetime__", new LocalDateTime()); for (String key : _map.keySet()) { st.add(key, _map.get(key)); } return _make(st); } private String _make(ST st) { return st.render(locale); } class ModelFormatRenderer implements ModelAdaptor { private Property getProperty(Class<?> beanClass, String name) { return Mapper.of(beanClass).getProperty(name); } private String getSelectionValue(Property prop, Object o, Object value) { if(value == null) { return ""; } MetaSelectItem item = Beans.get(MetaSelectItemRepository.class).all() .filter("self.select.name = ?1 AND self.value = ?2", prop.getSelection(), value).fetchOne(); if (item != null) { return item.getTitle(); } return value == null ? "" : value.toString(); } @Override public Object getProperty(Interpreter interp, ST self, Object o, Object property, String propertyName) { Property prop = this.getProperty(o.getClass(), (String) property); ModelAdaptor adap = self.groupThatCreatedThisInstance.getModelAdaptor(ObjectModelAdaptor.class); if (prop == null || Strings.isNullOrEmpty(prop.getSelection())) { return adap.getProperty(interp, self, o, property, propertyName); } Object value = adap.getProperty(interp, self, o, property, propertyName); return getSelectionValue(prop, o, value); } } class LocalDateRenderer implements AttributeRenderer { @Override public String toString(Object o, String formatString, Locale locale) { if ( formatString==null ) return o.toString(); LocalDate ld = (LocalDate) o; return ld.toString(formatString); } } class LocalDateTimeRenderer implements AttributeRenderer { @Override public String toString(Object o, String formatString, Locale locale) { if ( formatString==null ) return o.toString(); LocalDateTime ld = (LocalDateTime) o; return ld.toString(formatString); } } class LocalTimeRenderer implements AttributeRenderer { @Override public String toString(Object o, String formatString, Locale locale) { if ( formatString==null ) return o.toString(); LocalTime ld = (LocalTime) o; return ld.toString(formatString); } } }