/**
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/
package com.latinojoel.di.trans.steps.pushnotifications.apple;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleFileException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.exception.KettleValueException;
import org.pentaho.di.core.row.RowDataUtil;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStep;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;
import com.notnoop.apns.APNS;
import com.notnoop.apns.ApnsService;
import com.notnoop.apns.ApnsServiceBuilder;
import com.notnoop.apns.PayloadBuilder;
/**
* This class is responsible to processing the data rows.
*
* @author <a href="mailto:jlatino@sapo.pt">Joel Latino</a>
* @since 1.0.1
*/
public class PushNotification extends BaseStep implements StepInterface {
/** for i18n purposes. **/
private static final Class<?> PKG = PushNotification.class;
private PushNotificationMeta meta;
private PushNotificationData data;
public PushNotification(
StepMeta s, StepDataInterface stepDataInterface, int c, TransMeta t, Trans dis) {
super(s, stepDataInterface, c, t, dis);
}
/**
* {@inheritDoc}
*/
@Override
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
this.meta = (PushNotificationMeta) smi;
this.data = (PushNotificationData) sdi;
final Object[] r = getRow();
if (r == null) {
setOutputDone();
return false;
}
try {
if (first) {
first = false;
data.outputRowMeta = super.getInputRowMeta().clone();
data.nrPrevFields = data.outputRowMeta.size();
meta.getFields(data.outputRowMeta, getStepname(), null, null, this);
data.insertRowMeta = new RowMeta();
data.customFieldsDataPushValueNrs = new ArrayList<Integer>();
data.locArgDataPushValueNrs = new ArrayList<Integer>();
for (int i = 0; i < meta.getCustomFieldsDataPush().size(); i++) {
data.customFieldsDataPushValueNrs.add(getInputRowMeta().indexOfValue(
meta.getCustomFieldsDataPush().get(i)));
if (data.customFieldsDataPushValueNrs.get(i) < 0) {
throw new KettleStepException(BaseMessages.getString(PKG,
"ApplePushNotification.Exception.FieldRequired", meta.getCustomFieldsDataPush()
.get(i)));
}
}
for (int i = 0; i < meta.getLocalizedArgumentsDataPush().size(); i++) {
data.locArgDataPushValueNrs.add(getInputRowMeta().indexOfValue(
meta.getLocalizedArgumentsDataPush().get(i)));
if (data.locArgDataPushValueNrs.get(i) < 0) {
throw new KettleStepException(BaseMessages.getString(PKG,
"ApplePushNotification.Exception.FieldRequired", meta
.getLocalizedArgumentsDataPush()
.get(i)));
}
}
// Cache the position of the device token field
cachePosition();
} // end if first
final Object[] outputRow = RowDataUtil.allocateRowData(data.outputRowMeta.size());
for (int i = 0; i < data.nrPrevFields; i++) {
outputRow[i] = r[i];
}
final Date res = sendPush(getInputRowMeta(), r);
outputRow[data.nrPrevFields] = res;
putRow(data.outputRowMeta, outputRow);
if (checkFeedback(getLinesRead())) {
if (log.isBasic()) {
logBasic("Linenr " + getLinesRead()); // Some basic logging
}
}
} catch (Exception e) {
if (getStepMeta().isDoingErrorHandling()) {
putError(getInputRowMeta(), r, 1L, e.toString(), null, "PUSHAPPLE001");
} else {
new KettleStepException(e);
}
}
return true;
}
/**
* Sends the apple push notification.
*
* @param rowMeta the row meta data.
* @param r the row data.
* @return the date of inactive date the registration id provided.
* @throws KettleFileException the kettle file exception.
* @throws KettleValueException the kettle value exception.
*/
private Date sendPush(RowMetaInterface rowMeta, Object[] r) throws KettleFileException,
KettleValueException {
if (r == null) { // Stop: last line or error encountered
if (log.isDetailed()) {
logDetailed("Last line inserted: stop");
}
return null;
}
final InputStream fileInputStream =
KettleVFS.getInputStream(environmentSubstitute(data.certificatePath));
ApnsServiceBuilder apnsServiceBuilder =
APNS.newService().withCert(fileInputStream, data.certificatePassword)
.asBatched(data.waitTime, data.maxWaitTime)
.withAppleDestination(!meta.isUseSandboxField());
if (meta.isNoErrorDetectionField()) {
apnsServiceBuilder = apnsServiceBuilder.withNoErrorDetection();
}
if (meta.isAsQueuedField()) {
apnsServiceBuilder = apnsServiceBuilder.asQueued();
}
final ApnsService service = apnsServiceBuilder.build();
PayloadBuilder payloadBuilder = APNS.newPayload();
if (meta.getBadgeField() != null && !"".equals(meta.getBadgeField())) {
payloadBuilder.badge(rowMeta.getInteger(r, data.indexOfBadgeField).intValue());
}
if (meta.isShrinksBodyField()) {
payloadBuilder =
payloadBuilder.shrinkBody(environmentSubstitute(meta.getShrinksPostfixField()));
}
if (meta.getSoundField() != null) {
payloadBuilder = payloadBuilder.sound(rowMeta.getString(r, data.indexOfSoundField));
}
if (meta.getAlertBodyField() != null) {
payloadBuilder = payloadBuilder.alertBody(rowMeta.getString(r, data.indexOfAlertBodyField));
}
if (meta.getActionLocalizedKeyField() != null) {
payloadBuilder =
payloadBuilder.actionKey(rowMeta.getString(r, data.indexOfActionLocalizedKeyField));
}
if (meta.getLocalizedKeyField() != null) {
payloadBuilder =
payloadBuilder.localizedKey(rowMeta.getString(r, data.indexOfLocalizedKeyField));
}
if (meta.getLocalizedArgumentsDataPush().size() > 0) {
for (int i = 0; i < meta.getLocalizedArgumentsDataPush().size(); i++) {
payloadBuilder = payloadBuilder.localizedArguments(getInputRowMeta().getString(r,
data.locArgDataPushValueNrs.get(i)));
}
}
if (meta.getLaunchImageField() != null) {
payloadBuilder =
payloadBuilder.launchImage(rowMeta.getString(r, data.indexOfLaunchImageField));
}
int idx = 0;
for (String cFieldStream : meta.getCustomFieldsStream()) {
payloadBuilder = payloadBuilder.customField(cFieldStream,
getInputRowMeta().getString(r, data.customFieldsDataPushValueNrs.get(idx)));
idx++;
}
final String payload = payloadBuilder.build();
if (log.isDetailed()) {
logDetailed("Payload: " + payload);
}
service.push(rowMeta.getString(r, data.indexOfDeviceTokenField), payload);
final Map<String, Date> inactiveDevices = service.getInactiveDevices();
return inactiveDevices.get(meta.getDeviceTokenField());
}
/**
* {@inheritDoc}
*/
@Override
public boolean init(StepMetaInterface smi, StepDataInterface sdi) {
meta = (PushNotificationMeta) smi;
data = (PushNotificationData) sdi;
if (super.init(smi, sdi)) {
if (meta.getCertificatePathField() != null) {
data.certificatePath = environmentSubstitute(meta.getCertificatePathField());
}
if (meta.getCertificatePasswordField() != null) {
data.certificatePassword = environmentSubstitute(meta.getCertificatePasswordField());
}
if (meta.getShrinksPostfixField() != null) {
data.shrinksPostfix = environmentSubstitute(meta.getShrinksPostfixField());
}
if (meta.getWaitTimeField() != null) {
data.waitTime = Integer.parseInt(environmentSubstitute(meta.getWaitTimeField()));
}
if (meta.getMaxWaitTimeField() != null) {
data.maxWaitTime = Integer.parseInt(environmentSubstitute(meta.getMaxWaitTimeField()));
}
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public void dispose(StepMetaInterface smi, StepDataInterface sdi) {
super.dispose(smi, sdi);
}
/**
* Run is were the action happens.
*/
public void run() {
logBasic("Starting to run...");
try {
while (processRow(meta, data) && !isStopped()) {
continue;
}
} catch (Exception e) {
logError("Unexpected error : " + e.toString());
logError(Const.getStackTracker(e));
setErrors(1);
stopAll();
} finally {
dispose(meta, data);
logBasic("Finished, processing " + getLinesRead() + " rows");
markStop();
}
}
/**
* Checks the fields positions.
*
* @throws KettleStepException the kettle step exception.
*/
private void cachePosition() throws KettleStepException {
if (meta.getDeviceTokenField() != null && data.indexOfDeviceTokenField < 0) {
final String realDeviceToken = environmentSubstitute(meta.getDeviceTokenField());
data.indexOfDeviceTokenField = getInputRowMeta().indexOfValue(realDeviceToken);
if (data.indexOfDeviceTokenField < 0) {
final String message =
"Unable to find table name field [" + realDeviceToken + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getBadgeField() != null && data.indexOfBadgeField < 0) {
final String realBadge = environmentSubstitute(meta.getBadgeField());
data.indexOfBadgeField = getInputRowMeta().indexOfValue(realBadge);
if (data.indexOfBadgeField < 0) {
final String message = "Unable to find table name field [" + realBadge + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getSoundField() != null && data.indexOfSoundField < 0) {
final String realSound = environmentSubstitute(meta.getSoundField());
data.indexOfSoundField = getInputRowMeta().indexOfValue(realSound);
if (data.indexOfSoundField < 0) {
final String message = "Unable to find table name field [" + realSound + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getAlertBodyField() != null && data.indexOfAlertBodyField < 0) {
final String realAlertBody = environmentSubstitute(meta.getAlertBodyField());
data.indexOfAlertBodyField = getInputRowMeta().indexOfValue(realAlertBody);
if (data.indexOfAlertBodyField < 0) {
final String message =
"Unable to find table name field [" + realAlertBody + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getActionLocalizedKeyField() != null && data.indexOfActionLocalizedKeyField < 0) {
final String realActionLocalizedKey =
environmentSubstitute(meta.getActionLocalizedKeyField());
data.indexOfActionLocalizedKeyField = getInputRowMeta().indexOfValue(realActionLocalizedKey);
if (data.indexOfActionLocalizedKeyField < 0) {
final String message =
"Unable to find table name field [" + realActionLocalizedKey + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getLocalizedKeyField() != null && data.indexOfLocalizedKeyField < 0) {
final String realLocalizedKey = environmentSubstitute(meta.getLocalizedKeyField());
data.indexOfLocalizedKeyField = getInputRowMeta().indexOfValue(realLocalizedKey);
if (data.indexOfLocalizedKeyField < 0) {
final String message =
"Unable to find table name field [" + realLocalizedKey + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
if (meta.getLaunchImageField() != null && data.indexOfLaunchImageField < 0) {
final String realLaunchImage = environmentSubstitute(meta.getLaunchImageField());
data.indexOfLaunchImageField = getInputRowMeta().indexOfValue(realLaunchImage);
if (data.indexOfLaunchImageField < 0) {
final String message =
"Unable to find table name field [" + realLaunchImage + "] in input row";
logError(message);
throw new KettleStepException(message);
}
}
}
}