Java tutorial
/** * Copyright (C) 2014 Maas Dianto (maas.dianto@gmail.com) * * Licensed 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 com.github.maasdi.di.trans.steps.mongodbdelete; import java.net.UnknownHostException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.pentaho.di.core.Const; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.row.RowMeta; import org.pentaho.di.core.row.RowMetaInterface; 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.mongodb.CommandResult; import com.mongodb.DBObject; import com.mongodb.MongoException; import com.mongodb.WriteResult; import com.github.maasdi.mongo.wrapper.MongoClientWrapperFactory; import com.mongodb.BasicDBObject; import com.mongodb.util.JSON; /** * Class MongoDbDelete, providing MongoDB delete functionality. User able to create criteria base on incoming fields. * * @author Maas Dianto (maas.dianto@gmail.com) */ public class MongoDbDelete extends BaseStep implements StepInterface { private static Class<?> PKG = MongoDbDelete.class; private MongoDbDeleteMeta meta; private MongoDbDeleteData data; protected int m_writeRetries = MongoDbDeleteMeta.RETRIES; protected int m_writeRetryDelay = MongoDbDeleteMeta.RETRY_DELAY; public MongoDbDelete(StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta, Trans trans) { super(stepMeta, stepDataInterface, copyNr, transMeta, trans); } @Override public boolean processRow(StepMetaInterface stepMetaInterface, StepDataInterface stepDataInterface) throws KettleException { Object[] row = getRow(); if (meta.isUseJsonQuery()) { if (first) { first = false; if (getInputRowMeta() == null) { data.outputRowMeta = new RowMeta(); } else { data.setOutputRowMeta(getInputRowMeta()); } data.init(MongoDbDelete.this); DBObject query = getQueryFromJSON(meta.getJsonQuery(), row); commitDelete(query, row); } else if (meta.isExecuteForEachIncomingRow()) { if (row == null) { disconnect(); setOutputDone(); return false; } if (!first) { DBObject query = getQueryFromJSON(meta.getJsonQuery(), row); commitDelete(query, row); } } if (row == null) { disconnect(); setOutputDone(); return false; } if (!isStopped()) { putRow(data.getOutputRowMeta(), row); } return true; } else { if (row == null) { disconnect(); setOutputDone(); return false; } if (first) { first = false; data.setOutputRowMeta(getInputRowMeta()); // first check our incoming fields against our meta data for // fields to delete RowMetaInterface rmi = getInputRowMeta(); // this fields we are going to use for mongo output List<MongoDbDeleteMeta.MongoField> mongoFields = meta.getMongoFields(); checkInputFieldsMatch(rmi, mongoFields); data.setMongoFields(meta.getMongoFields()); data.init(MongoDbDelete.this); } if (!isStopped()) { putRow(data.getOutputRowMeta(), row); DBObject query = MongoDbDeleteData.getQueryObject(data.m_userFields, getInputRowMeta(), row, MongoDbDelete.this); if (log.isDebug()) { logDebug(BaseMessages.getString(PKG, "MongoDbDelete.Message.Debug.QueryForDelete", query)); } // We have query delete if (query != null) { commitDelete(query, row); } } return true; } } @Override public boolean init(StepMetaInterface stepMetaInterface, StepDataInterface stepDataInterface) { if (super.init(stepMetaInterface, stepDataInterface)) { meta = (MongoDbDeleteMeta) stepMetaInterface; data = (MongoDbDeleteData) stepDataInterface; if (!Const.isEmpty(meta.getWriteRetries())) { try { m_writeRetries = Integer.parseInt(meta.getWriteRetries()); } catch (NumberFormatException ex) { m_writeRetries = MongoDbDeleteMeta.RETRIES; } } if (!Const.isEmpty(meta.getWriteRetryDelay())) { try { m_writeRetryDelay = Integer.parseInt(meta.getWriteRetryDelay()); } catch (NumberFormatException ex) { m_writeRetryDelay = MongoDbDeleteMeta.RETRY_DELAY; } } String hostname = environmentSubstitute(meta.getHostnames()); int port = Const.toInt(environmentSubstitute(meta.getPort()), MongoDbDeleteData.MONGO_DEFAULT_PORT); String db = environmentSubstitute(meta.getDbName()); String collection = environmentSubstitute(meta.getCollection()); try { if (Const.isEmpty(db)) { throw new Exception(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.NoDBSpecified")); } if (Const.isEmpty(collection)) { throw new Exception( BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.NoCollectionSpecified")); } if (!Const.isEmpty(meta.getAuthenticationUser())) { String authInfo = (meta.getUseKerberosAuthentication() ? BaseMessages.getString(PKG, "MongoDbDelete.Message.KerberosAuthentication", environmentSubstitute(meta.getAuthenticationUser())) : BaseMessages.getString(PKG, "MongoDbDelete.Message.NormalAuthentication", environmentSubstitute(meta.getAuthenticationUser()))); logBasic(authInfo); } data.setConnection(MongoClientWrapperFactory.createMongoClientWrapper(meta, this, log)); if (Const.isEmpty(collection)) { throw new KettleException( BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.NoCollectionSpecified")); } data.createCollection(db, collection); data.setCollection(data.getConnection().getCollection(db, collection)); return true; } catch (UnknownHostException ex) { logError(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.UnknownHost", hostname), ex); return false; } catch (Exception e) { logError(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.ProblemConnecting", hostname, "" + port), e); return false; } } return false; } @Override public void dispose(StepMetaInterface stepMetaInterface, StepDataInterface stepDataInterface) { if (data.cursor != null) { try { data.cursor.close(); } catch (KettleException e) { log.logError(e.getMessage()); } } if (data.clientWrapper != null) { try { data.clientWrapper.dispose(); } catch (KettleException e) { log.logError(e.getMessage()); } } super.dispose(stepMetaInterface, stepDataInterface); } protected void disconnect() { if (data != null) { try { data.getConnection().dispose(); } catch (KettleException e) { log.logError(e.getMessage()); } } } protected void commitDelete(DBObject deleteQuery, Object[] row) throws KettleException { int retrys = 0; MongoException lastEx = null; while (retrys <= m_writeRetries && !isStopped()) { WriteResult result = null; CommandResult cmd = null; try { logDetailed(BaseMessages.getString(PKG, "MongoDbDelete.Message.ExecutingQuery", deleteQuery)); result = data.getCollection().drop(deleteQuery); cmd = result.getLastError(); if (cmd != null && !cmd.ok()) { String message = cmd.getErrorMessage(); logError(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.MongoReported", message)); cmd.throwOnError(); } } catch (MongoException me) { lastEx = me; retrys++; if (retrys <= m_writeRetries) { logError(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.ErrorWritingToMongo", me.toString())); logBasic(BaseMessages.getString(PKG, "MongoDbDelete.Message.Retry", m_writeRetryDelay)); try { Thread.sleep(m_writeRetryDelay * 1000); // CHECKSTYLE:OFF } catch (InterruptedException e) { // CHECKSTYLE:ON } } } if (cmd != null && cmd.ok()) { break; } } if ((retrys > m_writeRetries || isStopped()) && lastEx != null) { // Send this one to the error stream if doing error handling if (getStepMeta().isDoingErrorHandling()) { putError(getInputRowMeta(), row, 1, lastEx.getMessage(), "", "MongoDbDelete"); } else { throw new KettleException(lastEx); } } } public DBObject getQueryFromJSON(String json, Object[] row) throws KettleException { DBObject query; String jsonQuery = environmentSubstitute(json); if (Const.isEmpty(jsonQuery)) { query = new BasicDBObject(); } else { if (meta.isExecuteForEachIncomingRow() && row != null) { jsonQuery = fieldSubstitute(jsonQuery, getInputRowMeta(), row); } query = (DBObject) JSON.parse(jsonQuery); } return query; } final void checkInputFieldsMatch(RowMetaInterface rmi, List<MongoDbDeleteMeta.MongoField> mongoFields) throws KettleException { if (mongoFields == null || mongoFields.isEmpty()) { throw new KettleException( BaseMessages.getString(PKG, "MongoDbDeleteDialog.ErrorMessage.NoFieldPathsDefined")); } Set<String> expected = new HashSet<String>(mongoFields.size(), 1); Set<String> actual = new HashSet<String>(rmi.getFieldNames().length, 1); for (MongoDbDeleteMeta.MongoField field : mongoFields) { String field1 = environmentSubstitute(field.m_incomingField1); String field2 = environmentSubstitute(field.m_incomingField2); expected.add(field1); if (!Const.isEmpty(field2)) { expected.add(field2); } } for (int i = 0; i < rmi.size(); i++) { String metaFieldName = rmi.getValueMeta(i).getName(); actual.add(metaFieldName); } // check that all expected fields is available in step input meta if (!actual.containsAll(expected)) { // in this case some fields willn't be found in input step meta expected.removeAll(actual); StringBuffer b = new StringBuffer(); for (String name : expected) { b.append("'").append(name).append("', "); } throw new KettleException(BaseMessages.getString(PKG, "MongoDbDelete.MongoField.Error.FieldsNotFoundInMetadata", b.toString())); } boolean found = actual.removeAll(expected); if (!found) { throw new KettleException(BaseMessages.getString(PKG, "MongoDbDelete.ErrorMessage.NotDeleteAnyFields")); } } }