1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.jumpmind.symmetric.ext;
21
22 import java.text.ParseException;
23 import java.util.Map;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.jumpmind.symmetric.load.IDataLoaderContext;
28 import org.jumpmind.symmetric.load.IDataLoaderFilter;
29 import org.jumpmind.symmetric.load.StatementBuilder.DmlType;
30
31 /***
32 * A convenience class that allows the end user to template a message using
33 * SymmetricDS filter data.
34 * </p>
35 * You may use %COLUMN% formatted tokens in your template data which will be
36 * replaced by data coming in through the filter. The following tokens are also
37 * supported:
38 * <ol>
39 * <li>%DMLTYPE% - evaluates to INSERT, UPDATE or DELETE</li>
40 * <li>%TIMESTAMP% - evaluates to ms value returned by
41 * System.currentTimeInMillis()</li>
42 * </ol>
43 * </p>
44 * If you have special formatting needs, implement the {@link IFormat} interface
45 * and map your formatter to the column you want to 'massage.'
46 */
47 public class TemplatedPublisherFilter extends AbstractTextPublisherFilter {
48
49 static final Log logger = LogFactory.getLog(TemplatedPublisherFilter.class);
50
51 private String headerTableTemplate;
52 private String footerTableTemplate;
53 private String contentTableTemplate;
54 private Map<String, IFormat> columnNameToDataFormatter;
55 private boolean processDelete = true;
56 private boolean processInsert = true;
57 private boolean processUpdate = true;
58
59 private IDataLoaderFilter dataFilter;
60
61 @Override
62 protected String addTextElementForDelete(IDataLoaderContext ctx, String[] keys) {
63 if (this.dataFilter == null || this.dataFilter.filterDelete(ctx, keys)) {
64 String template = null;
65 if (processDelete) {
66 template = contentTableTemplate;
67 if (template != null) {
68 template = fillOutTemplate(DmlType.DELETE, template, ctx, null, keys);
69 }
70 }
71 return template;
72 } else {
73 return null;
74 }
75 }
76
77 @Override
78 protected String addTextElementForInsert(IDataLoaderContext ctx, String[] data) {
79 if (this.dataFilter == null || this.dataFilter.filterInsert(ctx, data)) {
80 String template = null;
81 if (processInsert) {
82 template = contentTableTemplate;
83 if (template != null) {
84 template = fillOutTemplate(DmlType.INSERT, template, ctx, data, null);
85 }
86 }
87 return template;
88 } else {
89 return null;
90 }
91 }
92
93 @Override
94 protected String addTextElementForUpdate(IDataLoaderContext ctx, String[] data, String[] keys) {
95 if (this.dataFilter == null || this.dataFilter.filterUpdate(ctx, data, keys)) {
96 String template = null;
97 if (processUpdate) {
98 template = contentTableTemplate;
99 if (template != null) {
100 template = fillOutTemplate(DmlType.UPDATE, template, ctx, data, keys);
101 }
102 }
103 return template;
104 } else {
105 return null;
106 }
107 }
108
109 @Override
110 protected String addTextFooter(IDataLoaderContext ctx) {
111 return footerTableTemplate;
112 }
113
114 @Override
115 protected String addTextHeader(IDataLoaderContext ctx) {
116 return headerTableTemplate;
117 }
118
119 protected String fillOutTemplate(DmlType dmlType, String template, IDataLoaderContext ctx, String[] data,
120 String[] keys) {
121 String[] colNames = null;
122
123 if (data == null) {
124 colNames = ctx.getKeyNames();
125 data = keys;
126 } else {
127 colNames = ctx.getColumnNames();
128 }
129
130 for (int i = 0; i < data.length; i++) {
131 String col = colNames[i];
132 template = replace(template, col, format(col, data[i]));
133 }
134
135 template = template.replace("DMLTYPE", dmlType.name());
136 template = template.replace("TIMESTAMP", Long.toString(System.currentTimeMillis()));
137
138 return template;
139 }
140
141 protected String format(String col, String data) {
142 if (columnNameToDataFormatter != null) {
143 IFormat formatter = columnNameToDataFormatter.get(col);
144 if (formatter != null) {
145 try {
146 data = formatter.format(data);
147 } catch (ParseException e) {
148 throw new RuntimeException(e);
149 }
150 }
151 }
152 return data;
153 }
154
155 protected String replace(String template, String token, String value) {
156 if (value == null) {
157 value = "";
158 }
159
160 if (template != null) {
161 template = template.replace("%" + token + "%", value);
162 }
163
164 return template;
165 }
166
167 public void setColumnNameToDataFormatter(Map<String, IFormat> columnNameToDataFormatter) {
168 this.columnNameToDataFormatter = columnNameToDataFormatter;
169 }
170
171 public void setProcessDelete(boolean processDeletes) {
172 this.processDelete = processDeletes;
173 }
174
175 public void setProcessInsert(boolean processInserts) {
176 this.processInsert = processInserts;
177 }
178
179 public void setProcessUpdate(boolean processUpdates) {
180 this.processUpdate = processUpdates;
181 }
182
183 public void setHeaderTableTemplate(String headerTableTemplate) {
184 this.headerTableTemplate = headerTableTemplate;
185 }
186
187 public void setFooterTableTemplate(String footerTableTemplate) {
188 this.footerTableTemplate = footerTableTemplate;
189 }
190
191 public void setContentTableTemplate(String contentTableTemplate) {
192 this.contentTableTemplate = contentTableTemplate;
193 }
194
195 public interface IFormat {
196 public String format(String data) throws ParseException;
197 }
198
199 public void setDataFilter(IDataLoaderFilter dataFilter) {
200 this.dataFilter = dataFilter;
201 }
202
203 }