/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.apache.camel.component.smpp;
import java.nio.charset.Charset;
import org.apache.camel.Message;
import org.jsmpp.bean.Alphabet;
import org.jsmpp.extra.NegativeResponseException;
import org.jsmpp.session.SMPPSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class SmppSmCommand extends AbstractSmppCommand {
// FIXME: these constants should be defined somewhere in jSMPP:
public static final int SMPP_NEG_RESPONSE_MSG_TOO_LONG = 1;
protected Charset ascii = Charset.forName("US-ASCII");
protected Charset latin1 = Charset.forName("ISO-8859-1");
protected Charset defaultCharset;
private final Logger logger = LoggerFactory.getLogger(SmppSmCommand.class);
public SmppSmCommand(SMPPSession session, SmppConfiguration config) {
super(session, config);
defaultCharset = Charset.forName(config.getEncoding());
}
protected byte[][] splitBody(Message message) throws SmppException {
byte[] shortMessage = getShortMessage(message);
SmppSplitter splitter = createSplitter(message);
byte[][] segments = splitter.split(shortMessage);
if (segments.length > 1) {
// Message body is split into multiple parts,
// check if this is permitted
SmppSplittingPolicy policy = getSplittingPolicy(message);
switch(policy) {
case ALLOW:
return segments;
case TRUNCATE:
return new byte[][] {java.util.Arrays.copyOfRange(shortMessage, 0, segments[0].length)};
case REJECT:
// FIXME - JSMPP needs to have an enum of the negative response
// codes instead of just using them like this
NegativeResponseException nre = new NegativeResponseException(SMPP_NEG_RESPONSE_MSG_TOO_LONG);
throw new SmppException(nre);
default:
throw new SmppException("Unknown splitting policy: " + policy);
}
} else {
return segments;
}
}
private SmppSplittingPolicy getSplittingPolicy(Message message) throws SmppException {
if (message.getHeaders().containsKey(SmppConstants.SPLITTING_POLICY)) {
String policyName = message.getHeader(SmppConstants.SPLITTING_POLICY, String.class);
return SmppSplittingPolicy.fromString(policyName);
}
return config.getSplittingPolicy();
}
protected SmppSplitter createSplitter(Message message) throws SmppException {
SmppSplitter splitter;
// use the splitter if provided via header
if (message.getHeaders().containsKey(SmppConstants.DATA_SPLITTER)) {
splitter = message.getHeader(SmppConstants.DATA_SPLITTER, SmppSplitter.class);
if (null != splitter) {
return splitter;
}
throw new SmppException("Invalid splitter given. Must be instance of SmppSplitter");
}
Alphabet alphabet = determineAlphabet(message);
String body = message.getBody(String.class);
if (SmppUtils.is8Bit(alphabet)) {
splitter = new Smpp8BitSplitter(body.length());
} else if (alphabet == Alphabet.ALPHA_UCS2) {
splitter = new SmppUcs2Splitter(body.length());
} else {
splitter = new SmppDefaultSplitter(body.length());
}
return splitter;
}
protected final byte[] getShortMessage(Message message) {
if (has8bitDataCoding(message)) {
return message.getBody(byte[].class);
} else {
byte providedAlphabet = getProvidedAlphabet(message);
Alphabet determinedAlphabet = determineAlphabet(message);
Charset charset = determineCharset(message, providedAlphabet, determinedAlphabet.value());
String body = message.getBody(String.class);
return body.getBytes(charset);
}
}
private static boolean has8bitDataCoding(Message message) {
Byte dcs = message.getHeader(SmppConstants.DATA_CODING, Byte.class);
if (dcs != null) {
return SmppUtils.is8Bit(Alphabet.parseDataCoding(dcs.byteValue()));
} else {
Byte alphabet = message.getHeader(SmppConstants.ALPHABET, Byte.class);
return alphabet != null && SmppUtils.is8Bit(Alphabet.valueOf(alphabet));
}
}
private byte getProvidedAlphabet(Message message) {
byte alphabet = config.getAlphabet();
if (message.getHeaders().containsKey(SmppConstants.ALPHABET)) {
alphabet = message.getHeader(SmppConstants.ALPHABET, Byte.class);
}
return alphabet;
}
private Charset getCharsetForMessage(Message message) {
if (message.getHeaders().containsKey(SmppConstants.ENCODING)) {
String encoding = message.getHeader(SmppConstants.ENCODING, String.class);
if (Charset.isSupported(encoding)) {
return Charset.forName(encoding);
} else {
logger.warn("Unsupported encoding \"{}\" requested in header.", encoding);
}
}
return null;
}
private Charset determineCharset(Message message, byte providedAlphabet, byte determinedAlphabet) {
Charset result = getCharsetForMessage(message);
if (result != null) {
return result;
}
if (providedAlphabet == Alphabet.ALPHA_UCS2.value()
|| (providedAlphabet == SmppConstants.UNKNOWN_ALPHABET && determinedAlphabet == Alphabet.ALPHA_UCS2.value())) {
// change charset to use multilang messages
return Charset.forName(SmppConstants.UCS2_ENCODING);
}
return defaultCharset;
}
private Alphabet determineAlphabet(Message message) {
String body = message.getBody(String.class);
byte alphabet = getProvidedAlphabet(message);
Charset charset = getCharsetForMessage(message);
if (charset == null) {
charset = defaultCharset;
}
Alphabet alphabetObj;
if (alphabet == SmppConstants.UNKNOWN_ALPHABET) {
alphabetObj = Alphabet.ALPHA_UCS2;
if (isLatin1Compatible(charset)) {
byte[] messageBytes = body.getBytes(charset);
if (SmppUtils.isGsm0338Encodeable(messageBytes)) {
alphabetObj = Alphabet.ALPHA_DEFAULT;
}
}
} else {
alphabetObj = Alphabet.valueOf(alphabet);
}
return alphabetObj;
}
private boolean isLatin1Compatible(Charset c) {
if (c.equals(ascii) || c.equals(latin1)) {
return true;
}
return false;
}
}