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  
21  package org.jumpmind.symmetric.transport;
22  
23  import java.io.IOException;
24  import java.net.URLDecoder;
25  import java.net.URLEncoder;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.lang.math.NumberUtils;
32  import org.jumpmind.symmetric.common.Constants;
33  import org.jumpmind.symmetric.model.BatchInfo;
34  import org.jumpmind.symmetric.model.IncomingBatchHistory;
35  import org.jumpmind.symmetric.model.IncomingBatchHistory.Status;
36  import org.jumpmind.symmetric.web.WebConstants;
37  
38  abstract public class AbstractTransportManager {
39  
40      protected String getAcknowledgementData(String nodeId, List<IncomingBatchHistory> list) throws IOException {
41          StringBuilder builder = new StringBuilder();
42          for (IncomingBatchHistory status : list) {
43              Object value = null;
44              if (status.getStatus() == Status.OK || status.getStatus() == Status.SK) {
45                  value = WebConstants.ACK_BATCH_OK;
46              } else {
47                  value = status.getFailedRowNumber();
48              }
49              append(builder, WebConstants.ACK_BATCH_NAME + status.getBatchId(), value);
50          }
51  
52          // For backwards compatibility with 1.3 and earlier, the first line is
53          // the
54          // original acknowledgement data and the second line contains more
55          // information
56          builder.append("\n");
57          for (IncomingBatchHistory status : list) {
58              long batchId = status.getBatchId();
59              append(builder, WebConstants.ACK_NODE_ID + batchId, nodeId);
60              append(builder, WebConstants.ACK_NETWORK_MILLIS + batchId, status.getNetworkMillis());
61              append(builder, WebConstants.ACK_FILTER_MILLIS + batchId, status.getFilterMillis());
62              append(builder, WebConstants.ACK_DATABASE_MILLIS + batchId, status.getDatabaseMillis());
63              append(builder, WebConstants.ACK_BYTE_COUNT + batchId, status.getByteCount());
64  
65              if (status.getStatus() == Status.ER) {
66                  append(builder, WebConstants.ACK_SQL_STATE + batchId, status.getSqlState());
67                  append(builder, WebConstants.ACK_SQL_CODE + batchId, status.getSqlCode());
68                  append(builder, WebConstants.ACK_SQL_MESSAGE + batchId, status.getSqlMessage());
69              }
70          }
71          return builder.toString();
72      }
73  
74      protected void append(StringBuilder builder, String name, Object value) throws IOException {
75          int len = builder.length();
76          if (len > 0 && builder.charAt(len - 1) != '?') {
77              builder.append("&");
78          }
79          if (value == null) {
80              value = "";
81          }
82          builder.append(name).append("=").append(URLEncoder.encode(value.toString(), Constants.ENCODING));
83      }
84  
85      public List<BatchInfo> readAcknowledgement(String parameterString1, String parameterString2) throws IOException {
86          return readAcknowledgement(parameterString1 + "&" + parameterString2);
87      }
88  
89      public List<BatchInfo> readAcknowledgement(String parameterString) throws IOException {
90          Map<String, Object> parameters = getParametersFromQueryUrl(parameterString.replace("\n", ""));
91          return readAcknowledgement(parameters);
92      }
93  
94      public static List<BatchInfo> readAcknowledgement(Map<String, Object> parameters) {
95          List<BatchInfo> batches = new ArrayList<BatchInfo>();
96          for (String parameterName : parameters.keySet()) {
97              if (parameterName.startsWith(WebConstants.ACK_BATCH_NAME)) {
98                  long batchId = NumberUtils.toLong(parameterName.substring(WebConstants.ACK_BATCH_NAME.length()));
99                  BatchInfo batchInfo = getBatchInfo(parameters, batchId);
100                 batches.add(batchInfo);
101             }
102         }
103         return batches;
104     }
105 
106     private static BatchInfo getBatchInfo(Map<String, Object> parameters, long batchId) {
107         BatchInfo batchInfo = new BatchInfo(batchId);
108         batchInfo.setNodeId(getParam(parameters, WebConstants.ACK_NODE_ID + batchId));
109         batchInfo.setNetworkMillis(getParamAsNum(parameters, WebConstants.ACK_NETWORK_MILLIS + batchId));
110         batchInfo.setFilterMillis(getParamAsNum(parameters, WebConstants.ACK_FILTER_MILLIS + batchId));
111         batchInfo.setDatabaseMillis(getParamAsNum(parameters, WebConstants.ACK_DATABASE_MILLIS + batchId));
112         batchInfo.setByteCount(getParamAsNum(parameters, WebConstants.ACK_BYTE_COUNT + batchId));
113         String status = getParam(parameters, WebConstants.ACK_BATCH_NAME + batchId, "").trim();
114         batchInfo.setOk(status.equalsIgnoreCase(WebConstants.ACK_BATCH_OK));
115 
116         if (!batchInfo.isOk()) {
117             batchInfo.setErrorLine(NumberUtils.toLong(status));
118             batchInfo.setSqlState(getParam(parameters, WebConstants.ACK_SQL_STATE + batchId));
119             batchInfo.setSqlCode((int) getParamAsNum(parameters, WebConstants.ACK_SQL_CODE + batchId));
120             batchInfo.setSqlMessage(getParam(parameters, WebConstants.ACK_SQL_MESSAGE + batchId));
121         }
122         return batchInfo;
123     }
124 
125     protected static Map<String, Object> getParametersFromQueryUrl(String parameterString) throws IOException {
126         Map<String, Object> parameters = new HashMap<String, Object>();
127         String[] tokens = parameterString.split("&");
128         for (String param : tokens) {
129             String[] nameValuePair = param.split("=");
130             if (nameValuePair.length == 2) {
131                 parameters.put(nameValuePair[0], URLDecoder.decode(nameValuePair[1], Constants.ENCODING));
132             }
133         }
134         return parameters;
135     }
136 
137     private static long getParamAsNum(Map<String, Object> parameters, String parameterName) {
138         return NumberUtils.toLong(getParam(parameters, parameterName));
139     }
140 
141     private static String getParam(Map<String, Object> parameters, String parameterName, String defaultValue) {
142         String value = getParam(parameters, parameterName);
143         return value == null ? defaultValue : value;
144     }
145 
146     private static String getParam(Map<String, Object> parameters, String parameterName) {
147         Object value = parameters.get(parameterName);
148         if (value instanceof String[]) {
149             String[] arrayValue = (String[]) value;
150             if (arrayValue.length > 0) {
151                 value = arrayValue[0];
152             }
153         }
154         return (String) value;
155     }
156 
157 }