/* jBilling - The Enterprise Open Source Billing System Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde This file is part of jbilling. jbilling is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. jbilling is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with jbilling. If not, see <http://www.gnu.org/licenses/>. */ package com.sapienter.jbilling.server.provisioning.task; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import com.sapienter.jbilling.server.pluggableTask.PluggableTask; import com.sapienter.jbilling.server.pluggableTask.TaskException; import com.sapienter.jbilling.server.pluggableTask.admin.ParameterDescription; import com.sapienter.jbilling.server.util.Context; /** * CAI external provisioning plug-in. Contains logic for communicating * to the CAI system. Actual delivery of messages is left for * implementations of IExternalCommunication. The configuration file * jbilling-provisioning.xml is used for selecting the cai * IExternalCommunication class. */ public class CAIProvisioningTask extends PluggableTask implements IExternalProvisioning { public static final String PARAM_ID_DEFAULT = "cai"; public static final ParameterDescription PARAMETER_ID = new ParameterDescription("id", false, ParameterDescription.Type.STR); public static final ParameterDescription PARAMETER_REMOVE = new ParameterDescription("remove", false, ParameterDescription.Type.STR); public static final ParameterDescription PARAMETER_USERNAME = new ParameterDescription("username", true, ParameterDescription.Type.STR); public static final ParameterDescription PARAMETER_PASSWORD = new ParameterDescription("password", true, ParameterDescription.Type.STR); //initializer for pluggable params { descriptions.add(PARAMETER_ID); descriptions.add(PARAMETER_REMOVE); descriptions.add(PARAMETER_USERNAME); descriptions.add(PARAMETER_PASSWORD); } private static final Logger LOG = Logger.getLogger( CAIProvisioningTask.class); /** * Sends command to CAI system. Returns response. */ public Map<String, Object> sendRequest(String id, String command) throws TaskException { // construct final command string command = constructCommand(id, command); // send command and return results return parseResponse(sendCommand(command)); } /** * Removes '-' from UUID and uses it as the command's TRANSID. * Deletes any fields with values that match the 'remove' parameter. */ private String constructCommand(String id, String command) { // remove '-' from UUID to create a transaction id StringBuilder transIdBuilder = new StringBuilder(id); int dashIndex = transIdBuilder.indexOf("-"); while (dashIndex != -1) { transIdBuilder.delete(dashIndex, dashIndex + 1); dashIndex = transIdBuilder.indexOf("-", dashIndex); } id = transIdBuilder.toString(); // add the transaction id to the command string StringBuilder commandBuilder = new StringBuilder(command); int insertIndex = commandBuilder.indexOf(":", commandBuilder.indexOf(":") + 1); commandBuilder.insert(insertIndex, ":TRANSID," + id); // delete fields with values that match the remove parameter String removeValue = (String) parameters.get(PARAMETER_REMOVE.getName()); if (removeValue != null) { int removeValueIndex = removeValueIndex(commandBuilder, removeValue); while (removeValueIndex != -1) { int fieldStartIndex = commandBuilder.lastIndexOf(":", removeValueIndex); commandBuilder.delete(fieldStartIndex, removeValueIndex + 1 + removeValue.length()); removeValueIndex = removeValueIndex(commandBuilder, removeValue); } } return commandBuilder.toString(); } /** * Helper method for finding index of field values to be removed. */ private int removeValueIndex(StringBuilder commandBuilder, String removeValue) { int removeValueIndex = commandBuilder.indexOf("," + removeValue + ":"); if (removeValueIndex == -1) { removeValueIndex = commandBuilder.indexOf("," + removeValue + ";"); } return removeValueIndex; } /** * Method to login to the CAI system and send command. */ private String sendCommand(String command) throws TaskException{ IExternalCommunication cai = (IExternalCommunication) Context.getBean(Context.Name.CAI); // IExternalCommunication cai = new TelnetCommunication(); String username = (String) parameters.get(PARAMETER_USERNAME.getName()); if (username == null) { throw new TaskException("No '" + PARAMETER_USERNAME.getName() + "' plug-in " + "parameter found."); } String password = (String) parameters.get(PARAMETER_PASSWORD.getName()); if (username == null) { throw new TaskException("No '" + PARAMETER_PASSWORD.getName() + "' plug-in " + "parameter found."); } cai.connect(parameters); String response = cai.send("LOGIN:" + username + ":" + password + ";"); if (!response.equals("RESP:0;")) { throw new TaskException("Couldn't login with username: '" + username + "' and password: '" + password + "'. Response: " + response); } LOG.debug("Sending command: " + command); response = cai.send(command); LOG.debug("Received response: " + response); String logout = cai.send("LOGOUT;"); if (!logout.equals("RESP:0;")) { LOG.error("Logout error: " + logout); } cai.close(); return response; } /** * Method to parse the response from the CAI system into a Map. * If 'RESP' is '0', 'result' is 'success', otherwise 'fail'. */ private Map<String, Object> parseResponse(String response) throws TaskException { // response in the form of: // RESP:TRANSID,12345:0:NAME1,value1:NAME2,value2; Map<String, Object> results = new HashMap<String, Object>(); if (!response.substring(0, 5).equals("RESP:")) { throw new TaskException("Expected 'RESP:' in response, but got: " + response); } if (!response.substring(5,13).equals("TRANSID,")) { throw new TaskException("Expected 'TRANSID:' in response, but got: " + response); } // get up to ':'. this will be the TRANSID value int transidIndex = response.indexOf(':', 13); String value = response.substring(13, transidIndex); results.put("TRANSID", value); // get up to next ':' or ';', this will be the RESP value int respIndex = fieldSplitIndex(response, transidIndex + 1); value = response.substring(transidIndex + 1, respIndex); results.put("RESP", value); // set result value if (value.equals("0")) { results.put("result", "success"); } else { results.put("result", "fail"); } // rest of the fields // get to next ':' or ';', then within that, split by ',' int prevIndex = respIndex; int fieldSplitIndex = fieldSplitIndex(response, prevIndex + 1); while (fieldSplitIndex != -1) { String str = response.substring(prevIndex + 1, fieldSplitIndex); int commaIndex = str.indexOf(','); results.put(str.substring(0, commaIndex), str.substring(commaIndex + 1, str.length())); prevIndex = fieldSplitIndex; fieldSplitIndex = fieldSplitIndex(response, prevIndex + 1); } return results; } /** * Helper method for finding the index of field separators */ private int fieldSplitIndex(String str, int fromIndex) { int index = str.indexOf(':', fromIndex); if (index == -1) { index = str.indexOf(';', fromIndex); } return index; } /** * Returns the id of the task. */ public String getId() { String id = (String) parameters.get(PARAMETER_ID.getName()); if (id != null) { return id; } return PARAM_ID_DEFAULT; } /** * For allowing unit testing outside jBilling. */ public void setParameters(HashMap<String, String> parameters) { this.parameters = parameters; } }