/** * Licensed to JumpMind Inc under one or more contributor * license agreements. See the NOTICE file distributed * with this work for additional information regarding * copyright ownership. JumpMind Inc licenses this file * to you under the GNU General Public License, version 3.0 (GPLv3) * (the "License"); you may not use this file except in compliance * with the License. * * You should have received a copy of the GNU General Public License, * version 3.0 (GPLv3) along with this library; if not, see * <http://www.gnu.org/licenses/>. * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.jumpmind.symmetric.transport; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.jumpmind.exception.IoException; import org.jumpmind.symmetric.common.Constants; import org.jumpmind.symmetric.io.IoConstants; import org.jumpmind.symmetric.model.BatchAck; import org.jumpmind.symmetric.model.IncomingBatch; import org.jumpmind.symmetric.model.OutgoingBatch; import org.jumpmind.symmetric.model.IncomingBatch.Status; import org.jumpmind.symmetric.service.IExtensionService; import org.jumpmind.symmetric.web.WebConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; abstract public class AbstractTransportManager { protected final Logger log = LoggerFactory.getLogger(getClass()); protected IExtensionService extensionService; public AbstractTransportManager() { } public AbstractTransportManager(IExtensionService extensionService) { this.extensionService = extensionService; } /** * Build the url for remote node communication. Use the remote sync_url * first, if it is null or blank, then use the registration url instead. */ public String resolveURL(String syncUrl, String registrationUrl) { if (StringUtils.isBlank(syncUrl) || syncUrl.startsWith(Constants.PROTOCOL_NONE)) { log.debug("Using the registration URL to contact the remote node because the syncURL for the node is blank"); return registrationUrl; } try { URI uri = new URI(syncUrl); for (ISyncUrlExtension handler : extensionService.getExtensionPointList(ISyncUrlExtension.class)) { syncUrl = handler.resolveUrl(uri); uri = new URI(syncUrl); } } catch (URISyntaxException e) { log.error(e.getMessage(),e); } return syncUrl; } public String getAcknowledgementData(boolean requires13Format, String nodeId, List<IncomingBatch> list) { StringBuilder builder = new StringBuilder(); for (IncomingBatch batch : list) { builder.append(getAcknowledgementData(requires13Format, nodeId, batch)); } return builder.toString(); } public String getAcknowledgementData(boolean requires13Format, String nodeId, IncomingBatch batch) { StringBuilder builder = new StringBuilder(); if (!requires13Format) { long batchId = batch.getBatchId(); Object value = null; if (batch.getStatus() == Status.OK) { value = WebConstants.ACK_BATCH_OK; } else if (batch.getStatus() != Status.ER) { value = WebConstants.ACK_BATCH_LD; } else { value = batch.getFailedRowNumber(); } append(builder, WebConstants.ACK_BATCH_NAME + batch.getBatchId(), value); append(builder, WebConstants.ACK_NODE_ID + batchId, nodeId); append(builder, WebConstants.ACK_NETWORK_MILLIS + batchId, batch.getNetworkMillis()); append(builder, WebConstants.ACK_FILTER_MILLIS + batchId, batch.getFilterMillis()); append(builder, WebConstants.ACK_DATABASE_MILLIS + batchId, batch.getDatabaseMillis()); append(builder, WebConstants.ACK_BYTE_COUNT + batchId, batch.getByteCount()); if (batch.getIgnoreCount() > 0) { append(builder, WebConstants.ACK_IGNORE_COUNT + batchId, batch.getIgnoreCount()); } if (batch.getStatus() == Status.ER) { append(builder, WebConstants.ACK_SQL_STATE + batchId, batch.getSqlState()); append(builder, WebConstants.ACK_SQL_CODE + batchId, batch.getSqlCode()); append(builder, WebConstants.ACK_SQL_MESSAGE + batchId, batch.getSqlMessage()); } } else { Object value = null; if (batch.getStatus() == Status.OK || batch.getStatus() == Status.IG) { value = WebConstants.ACK_BATCH_OK; } else { value = batch.getFailedRowNumber(); } append(builder, WebConstants.ACK_BATCH_NAME + batch.getBatchId(), value); } return builder.toString(); } protected static void append(StringBuilder builder, String name, Object value) { try { int len = builder.length(); if (len > 0 && builder.charAt(len - 1) != '?') { builder.append("&"); } if (value == null) { value = ""; } builder.append(name).append("=") .append(URLEncoder.encode(value.toString(), IoConstants.ENCODING)); } catch (IOException ex) { throw new IoException(ex); } } public List<BatchAck> readAcknowledgement(String parameterString1, String parameterString2) throws IOException { return readAcknowledgement(parameterString1 + "&" + parameterString2); } public List<BatchAck> readAcknowledgement(String parameterString) throws IOException { Map<String, Object> parameters = getParametersFromQueryUrl(parameterString.replace("\n", "")); return readAcknowledgement(parameters); } public static List<BatchAck> readAcknowledgement(Map<String, ? extends Object> parameters) { List<BatchAck> batches = new ArrayList<BatchAck>(); for (String parameterName : parameters.keySet()) { if (parameterName.startsWith(WebConstants.ACK_BATCH_NAME)) { long batchId = NumberUtils.toLong(parameterName.substring(WebConstants.ACK_BATCH_NAME.length())); BatchAck batchInfo = getBatchInfo(parameters, batchId); batches.add(batchInfo); } } return batches; } private static BatchAck getBatchInfo(Map<String, ? extends Object> parameters, long batchId) { BatchAck batchInfo = new BatchAck(batchId); String nodeId = getParam(parameters, WebConstants.ACK_NODE_ID + batchId); if (StringUtils.isBlank(nodeId)) { nodeId = getParam(parameters, WebConstants.NODE_ID); } batchInfo.setNodeId(nodeId); batchInfo.setNetworkMillis(getParamAsNum(parameters, WebConstants.ACK_NETWORK_MILLIS + batchId)); batchInfo.setFilterMillis(getParamAsNum(parameters, WebConstants.ACK_FILTER_MILLIS + batchId)); batchInfo.setDatabaseMillis(getParamAsNum(parameters, WebConstants.ACK_DATABASE_MILLIS + batchId)); batchInfo.setByteCount(getParamAsNum(parameters, WebConstants.ACK_BYTE_COUNT + batchId)); batchInfo.setIgnored(getParamAsBoolean(parameters, WebConstants.ACK_IGNORE_COUNT + batchId)); String status = getParam(parameters, WebConstants.ACK_BATCH_NAME + batchId, "").trim(); if (status.equalsIgnoreCase(WebConstants.ACK_BATCH_OK)) { batchInfo.setStatus(OutgoingBatch.Status.OK); } else if (status.equalsIgnoreCase(WebConstants.ACK_BATCH_LD)) { batchInfo.setStatus(OutgoingBatch.Status.LD); } else { batchInfo.setStatus(OutgoingBatch.Status.ER); batchInfo.setErrorLine(NumberUtils.toLong(status)); batchInfo.setSqlState(getParam(parameters, WebConstants.ACK_SQL_STATE + batchId)); batchInfo.setSqlCode((int) getParamAsNum(parameters, WebConstants.ACK_SQL_CODE + batchId)); batchInfo.setSqlMessage(getParam(parameters, WebConstants.ACK_SQL_MESSAGE + batchId)); } return batchInfo; } protected static Map<String, Object> getParametersFromQueryUrl(String parameterString) throws IOException { Map<String, Object> parameters = new HashMap<String, Object>(); String[] tokens = parameterString.split("&"); for (String param : tokens) { String[] nameValuePair = param.split("="); if (nameValuePair.length == 2) { parameters.put(nameValuePair[0], URLDecoder.decode(nameValuePair[1], IoConstants.ENCODING)); } } return parameters; } private static long getParamAsNum(Map<String, ? extends Object> parameters, String parameterName) { return NumberUtils.toLong(getParam(parameters, parameterName)); } private static boolean getParamAsBoolean(Map<String, ? extends Object> parameters, String parameterName) { return getParamAsNum(parameters, parameterName) > 0; } private static String getParam(Map<String, ? extends Object> parameters, String parameterName, String defaultValue) { String value = getParam(parameters, parameterName); return value == null ? defaultValue : value; } private static String getParam(Map<String, ? extends Object> parameters, String parameterName) { Object value = parameters.get(parameterName); if (value instanceof String[]) { String[] arrayValue = (String[]) value; if (arrayValue.length > 0) { value = StringUtils.trim(arrayValue[0]); } } return (String) value; } }