/* 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.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; 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.provisioning.task.mmsc.AddCustomerRequest; import com.sapienter.jbilling.server.provisioning.task.mmsc.DeleteCustomerRequest; import com.sapienter.jbilling.server.provisioning.task.mmsc.EfsBaseMSISDNRequest; import com.sapienter.jbilling.server.provisioning.task.mmsc.IMMSCHandlerFacade; import com.sapienter.jbilling.server.provisioning.task.mmsc.MMSCException_Exception; import com.sapienter.jbilling.server.provisioning.task.mmsc.MmscFacadeHandlerResponse; import com.sapienter.jbilling.server.provisioning.task.mmsc.ModifyCustomerRequest; import com.sapienter.jbilling.server.util.Context; /** * @author othman * * MMSC external provisioning plug-in. Contains logic for communicating * to MMSC webservice. Actual delivery of messages is left for * implementations of IMMSCCommunication. The configuration file * jbilling-provisioning.xml is used for selecting the mmsc * IMMSCCommunication class. */ public class MMSCProvisioningTask extends PluggableTask implements IExternalProvisioning { public static final String PARAM_ID_DEFAULT = "mmsc"; public static final String PARAM_ID = "id"; // MMSCProvisioningTask plugin parameters public static final ParameterDescription PARAM_LOGIN_PASSWORD= new ParameterDescription( "loginPassword" , true, ParameterDescription.Type.STR); public static final ParameterDescription PARAM_LOGIN_USER= new ParameterDescription( "loginUser" , true, ParameterDescription.Type.STR); public static final ParameterDescription PARAM_PORTAL_ID= new ParameterDescription( "portalId", true, ParameterDescription.Type.STR); public static final ParameterDescription PARAM_APPLICATION_ID= new ParameterDescription( "applicationId", true, ParameterDescription.Type.STR); public static final ParameterDescription PARAM_BNET= new ParameterDescription( "bnet", false, ParameterDescription.Type.STR); // other MMSC service interface parameters public static final ParameterDescription TRANSACTION_ID= new ParameterDescription( "transactionId", false, ParameterDescription.Type.STR); public static final ParameterDescription CHANNEL_ID= new ParameterDescription( "channeld", false, ParameterDescription.Type.STR); public static final ParameterDescription REFERENCE_ID= new ParameterDescription( "referenceId", false, ParameterDescription.Type.STR); public static final ParameterDescription TAG= new ParameterDescription( "tag", false, ParameterDescription.Type.STR); public static final ParameterDescription USER_ID= new ParameterDescription( "userId", false, ParameterDescription.Type.STR); public static final ParameterDescription MSISDN= new ParameterDescription( "msisdn", true, ParameterDescription.Type.STR); public static final ParameterDescription SUBSCRIPTION_TYPE= new ParameterDescription( "subscriptionType", true, ParameterDescription.Type.STR); public static final ParameterDescription MMS_CAPABILITY= new ParameterDescription( "mmsCapability", true, ParameterDescription.Type.STR); public static final ParameterDescription METHOD_NAME= new ParameterDescription( "methodName", true, ParameterDescription.Type.STR); // MMSC service methods names. These names should match the methods names in // IMMSCCommunication class public static final String ADD_CUSTOMER = "addCustomer"; public static final String MODIFY_CUSTOMER = "modifyCustomer"; public static final String DELETE_CUSTOMER = "deleteCustomer"; // MMSC Service-level error codes public static final String STATUS_CODE = "statusCode"; public static final String STATUS_MESSAGE = "statusMessage"; public static final int STATUS_CODE_OK = 0; public static final int STATUS_CODE_SERVICE_ERROR = -1; public static final int STATUS_CODE_MSISDN_ERROR = 1; public static final int STATUS_CODE_SUBSCRIPTION_ERROR = 2; public static final int STATUS_CODE_BNET_ERROR = 3; private static final Logger LOG = Logger.getLogger(MMSCProvisioningTask.class); //initializer for pluggable params { descriptions.add(PARAM_LOGIN_PASSWORD); descriptions.add(PARAM_LOGIN_USER); descriptions.add(PARAM_PORTAL_ID); descriptions.add(PARAM_APPLICATION_ID); descriptions.add(PARAM_BNET); descriptions.add(TRANSACTION_ID); descriptions.add(CHANNEL_ID); descriptions.add(REFERENCE_ID); descriptions.add(TAG); descriptions.add(USER_ID); descriptions.add(MSISDN); descriptions.add(SUBSCRIPTION_TYPE); descriptions.add(MMS_CAPABILITY); descriptions.add(METHOD_NAME); } /** * Sends command to MMSC system. Returns response. */ public Map<String, Object> sendRequest(String id, String command) throws TaskException { // send command and return results return parseResponse(sendCommand(command, id)); } /** * Method call MMSC webservice method. * * @param command * @param id * @return * @throws TaskException */ private MmscFacadeHandlerResponse sendCommand(String command, String id) throws TaskException { IMMSCHandlerFacade mmsc = (IMMSCHandlerFacade) Context .getBean(Context.Name.MMSC); MmscFacadeHandlerResponse response = null; Map<String, String> params = getParameters(command, id); if (params == null || params.isEmpty()) throw new TaskException("NULL or Empty Parameters List!"); String methodName = params.get(METHOD_NAME.getName()); if (methodName == null) throw new TaskException("Expected Method Name!"); try { if (methodName.equals(ADD_CUSTOMER)) { String subscriptionType = (String) params.get( SUBSCRIPTION_TYPE.getName()); if (subscriptionType == null) { throw new TaskException("parameter '" + SUBSCRIPTION_TYPE.getName() + "' is Mandatory "); } AddCustomerRequest request = new AddCustomerRequest(); populateRequest(request, params); request.setSubscriptionType(subscriptionType); response = mmsc.addCustomer(request); } else if (methodName.equals(MODIFY_CUSTOMER)) { String mmsCapability = (String) params.get(MMS_CAPABILITY.getName()); if (mmsCapability == null) { throw new TaskException("parameter '" + MMS_CAPABILITY.getName() + "' is Mandatory "); } ModifyCustomerRequest request = new ModifyCustomerRequest(); populateRequest(request, params); request.setMmsCapability(mmsCapability); response = mmsc.modifyCustomer(request); } else if (methodName.equals(DELETE_CUSTOMER)) { DeleteCustomerRequest request = new DeleteCustomerRequest(); populateRequest(request, params); response = mmsc.deleteCustomer(request); } else { throw new TaskException("webservice method '" + methodName + "' is Not Found! "); } } catch (MMSCException_Exception mmsce) { throw new TaskException(mmsce); } return response; } /** * Adds common parameters to request. */ private void populateRequest(EfsBaseMSISDNRequest request, Map<String, String> params) throws TaskException { request.setLoginUser((String) params.get(PARAM_LOGIN_USER.getName())); request.setLoginPassword((String) params.get(PARAM_LOGIN_PASSWORD.getName())); request.setPortalId((String) params.get(PARAM_PORTAL_ID.getName())); request.setApplicationId((String) params.get(PARAM_APPLICATION_ID.getName())); request.setTransactionId((String) params.get(TRANSACTION_ID.getName())); request.setChannelId((String) params.get(CHANNEL_ID.getName())); request.setReferenceId((String) params.get(REFERENCE_ID.getName())); request.setTag((String) params.get(TAG.getName())); request.setUserId((String) params.get(USER_ID.getName())); String msisdn = (String) params.get(MSISDN.getName()); if (msisdn == null) { throw new TaskException("parameter '" + MSISDN + "' is Mandatory "); } request.setMSISDN(msisdn); } /** * method to parse MMSC command * @param command * @return * @throws TaskException */ private Map<String, String> parseCommand(String command) throws TaskException { // sample command pattern to parse: // "addCustomer:msisdn,46701055555:subscriptionType,HK;" LOG.debug("parsing command string pattern: " + command); Map<String, String> params = new LinkedHashMap<String, String>(); StringTokenizer st = new StringTokenizer(command, ":;"); while (st.hasMoreTokens()) { String token = st.nextToken(); String[] entry = token.split(","); if (entry.length > 2) throw new TaskException( "Error parsing command: Expected two Tokens but found too many tokens: " + token); else if (entry.length == 1) { // found method name params.put(METHOD_NAME.getName(), entry[0]); } else { params.put(entry[0], entry[1]); } } return params; } /** * returns Parametres Map extracted from MMSC command String * * @param command * @param id * @return * @throws TaskException */ private Map<String, String> getParameters(String command, String id) throws TaskException { Map<String, String> params = new LinkedHashMap<String, String>(); // collect plugin parameters String username = (String) parameters.get(PARAM_LOGIN_USER.getName()); if (username == null) { throw new TaskException("No '" + PARAM_LOGIN_USER + "' plug-in " + "parameter found."); } params.put(PARAM_LOGIN_USER.getName(), username); String password = (String) parameters.get(PARAM_LOGIN_PASSWORD.getName()); if (password == null) { throw new TaskException("No '" + PARAM_LOGIN_PASSWORD.getName() + "' plug-in " + "parameter found."); } params.put(PARAM_LOGIN_PASSWORD.getName(), password); String portalId = (String) parameters.get(PARAM_PORTAL_ID.getName()); if (portalId == null) { throw new TaskException("No '" + PARAM_PORTAL_ID.getName() + "' plug-in " + "parameter found."); } params.put(PARAM_PORTAL_ID.getName(), portalId); String applicationId = (String) parameters.get(PARAM_APPLICATION_ID.getName()); if (applicationId == null) { throw new TaskException("No '" + PARAM_APPLICATION_ID.getName() + "' plug-in " + "parameter found."); } params.put(PARAM_APPLICATION_ID.getName(), applicationId); /* String bnet = (String) parameters.get(PARAM_BNET); if (bnet == null) { throw new TaskException("No '" + PARAM_BNET + "' plug-in " + "parameter found."); } params.put(PARAM_BNET, bnet); */ params.put(TRANSACTION_ID.getName(), id); Map<String, String> parsedCommand = parseCommand(command); // append parsed command key/value pairs params.putAll(parsedCommand); return params; } /** * Method to parse the response from the MMSC system into a Map. If * 'statusCode' is '0', 'result' is 'success', otherwise 'fail'. * * @param response * @return * @throws TaskException */ private Map<String, Object> parseResponse( MmscFacadeHandlerResponse response) throws TaskException { Map<String, Object> results = new HashMap<String, Object>(); String value = response.getTransactionId(); if (value == null) { throw new TaskException("Expected '" + TRANSACTION_ID.getName() + "' in response"); } // set TRANSACTION_ID value results.put(TRANSACTION_ID.getName(), value); int statusCode = response.getStatusCode(); // set STATUS_CODE value results.put(STATUS_CODE, "" + statusCode); // set result value if (statusCode == STATUS_CODE_OK) { results.put("result", "success"); } else { results.put("result", "fail"); } value = response.getStatusMessage(); if (value == null) { throw new TaskException("Expected '" + STATUS_MESSAGE + "' in response"); } results.put(STATUS_MESSAGE, value); return results; } /** * Returns the id of the task. */ public String getId() { String id = (String) parameters.get(PARAM_ID); 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; } }