001 /*
002 * ----------------------------------------------------------------------
003 * Copyright (C) 2009 Enrique Lara (k957@68k.org)
004 *
005 * TinLizard is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public License
007 * as published by the Free Software Foundation; either version 3.0
008 * of the License, or (at your option) any later version.
009 *
010 * TinLizard is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with TinLizard. If not, see http://www.gnu.org/licenses/.
017 * ----------------------------------------------------------------------
018 */
019 package tinlizard.dao.io;
020
021 import freemarker.template.Configuration;
022 import freemarker.template.DefaultObjectWrapper;
023 import freemarker.template.Template;
024
025 import tinlizard.dao.MashDao;
026
027 import tinlizard.util.Messages;
028
029 import java.io.File;
030 import java.io.FileNotFoundException;
031 import java.io.FileOutputStream;
032 import java.io.IOException;
033 import java.io.InputStream;
034 import java.io.Writer;
035 import java.util.HashMap;
036 import java.util.Locale;
037 import java.util.Map;
038
039 import org.apache.commons.lang.StringUtils;
040 import org.apache.log4j.Logger;
041
042 /**
043 * Freemarker implementation of MashDao.
044 */
045 public final class MashDaoImpl implements MashDao {
046 private static final Logger LOG = Logger.getLogger(MashDaoImpl.class);
047 private static final int BUFFER_SIZE = 128;
048 private String mashFilesDirectory;
049 private File mashDir = new File("/tmp");
050 private File resourcesDir = new File("/tmp");
051 private Configuration cfg = null;
052 private static final int SECONDS_PER_MINUTE = 60;
053 private int delayMinutes = 5;
054
055 public String getMashFilesDirectory() {
056 return mashFilesDirectory;
057 }
058
059 public void setMashFilesDirectory(final String mashFilesDirectory) {
060 this.mashFilesDirectory = mashFilesDirectory;
061
062 mashDir = new File(mashFilesDirectory);
063 resourcesDir = new File(mashDir, "resources");
064
065 if (!mashDir.isDirectory()) {
066 mashDir.mkdirs();
067 }
068
069 if (!resourcesDir.isDirectory()) {
070 resourcesDir.mkdir();
071 }
072
073 try {
074 cfg = new Configuration();
075 cfg.setDirectoryForTemplateLoading(mashDir);
076 cfg.setObjectWrapper(new DefaultObjectWrapper());
077 cfg.setTemplateUpdateDelay(delayMinutes * SECONDS_PER_MINUTE);
078 } catch (Exception e) {
079 throw new RuntimeException(Messages.error_0300(), e);
080 }
081 }
082
083 public File getResourcesFile(final String path) {
084 if (path.indexOf("..") != -1) {
085 //XXX consider logging warning.
086 return null;
087 }
088
089 File resFile = new File(resourcesDir, path);
090
091 if (!resFile.getParentFile().exists()) {
092 return null;
093 }
094
095 if (!resFile.exists()) {
096 String resourceClassPath = "/mash-files/resources" + path;
097
098 if (copyFromClasspath(resFile, resourceClassPath)) {
099 return resFile;
100 }
101 }
102
103 return null;
104 }
105
106 private boolean copyFromClasspath(final File resFile, final String resourceClassPath) {
107 InputStream is = getClass().getResourceAsStream(resourceClassPath);
108
109 if (is == null) {
110 return false;
111 }
112
113 if (!resFile.getParentFile().isDirectory()) {
114 resFile.getParentFile().mkdirs();
115 }
116
117 FileOutputStream os = null;
118
119 try {
120 os = new FileOutputStream(resFile);
121
122 byte[] buffer = new byte[BUFFER_SIZE];
123 int nRead = -1;
124
125 while ((nRead = is.read(buffer)) > -1) {
126 os.write(buffer, 0, nRead);
127 }
128
129 return true;
130 } catch (FileNotFoundException e) {
131 return false;
132 } catch (IOException e) {
133 return false;
134 } finally {
135 try {
136 is.close();
137 } catch (IOException e) {
138 LOG.trace("Ignore, nothing to do.");
139 }
140
141 if (os != null) {
142 try {
143 os.close();
144 } catch (IOException e) {
145 LOG.trace("Ignore, nothing to do.");
146 }
147 }
148 }
149 }
150
151 public void applyTemplate(final Object it, final String template, final Writer out, final Locale locale, final String username) {
152 try {
153 boolean foundTemplate = false;
154
155 String resourcePath = null;
156
157 Class<?> clazz = it.getClass();
158
159 while (!foundTemplate && !Object.class.equals(clazz)) {
160 if (LOG.isDebugEnabled()) {
161 LOG.debug("Class:" + clazz);
162 }
163
164 File classMashDir = getClassMashDir(clazz);
165 resourcePath = getResourcePath(clazz);
166
167 File templateFile = new File(classMashDir, template);
168 foundTemplate = templateFile.exists();
169
170 if (!foundTemplate) {
171 String resourceClassPath = "/mash-files/" + resourcePath + "/" + template;
172
173 if (LOG.isDebugEnabled()) {
174 LOG.debug("Check:" + resourceClassPath);
175 }
176
177 foundTemplate = copyFromClasspath(templateFile, resourceClassPath);
178 }
179
180 clazz = clazz.getSuperclass();
181 }
182
183 if (foundTemplate) {
184 if (LOG.isDebugEnabled()) {
185 LOG.debug("Found:" + resourcePath + "/" + template);
186 }
187
188 Map<Object, Object> root = new HashMap<Object, Object>();
189 root.put("it", it);
190
191 if (StringUtils.isNotBlank(username)) {
192 root.put("username", username);
193 }
194
195 Template temp = cfg.getTemplate(resourcePath + "/" + template, locale);
196 temp.process(root, out);
197 }
198 } catch (Exception e) {
199 LOG.info("Problems Applying template:" + template, e);
200 }
201 }
202
203 private String getResourcePath(final Class<?extends Object> clazz) {
204 String clazzName = clazz.getName();
205 String clazzDir = clazzName.replaceAll("\\.", "/");
206
207 return clazzDir;
208 }
209
210 private File getClassMashDir(final Class<?extends Object> clazz) {
211 String clazzName = clazz.getName();
212 String clazzDir = clazzName.replaceAll("\\.", "/");
213
214 return new File(mashDir, clazzDir);
215 }
216 }