View Javadoc

1   /*
2    * SymmetricDS is an open source database synchronization solution.
3    *   
4    * Copyright (C) Chris Henson <chenson42@users.sourceforge.net>
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 3 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see
18   * <http://www.gnu.org/licenses/>.
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 }