/* * Copyright 2007 T-Rank AS * * 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 no.trank.openpipe.jdbc.store; import java.util.Iterator; import javax.sql.DataSource; import org.apache.ws.jaxme.sqls.SQLFactory; import no.trank.openpipe.api.BasePipelineStep; import no.trank.openpipe.api.BaseSubPipeline; import no.trank.openpipe.api.PipelineException; import no.trank.openpipe.api.PipelineStepStatus; import no.trank.openpipe.api.SubPipeline; import no.trank.openpipe.api.document.Document; import no.trank.openpipe.api.document.DocumentOperation; import no.trank.openpipe.config.annotation.NotEmpty; import no.trank.openpipe.config.annotation.NotNull; /** * A pipeline step that tracks whether a document is new, updated or deleted using {@link IdStateHolder}. * * @version $Revision$ */ public class StateDocumentStep extends BasePipelineStep implements TableDescription { private IdStateHolder idStateHolder; @NotNull private DataSource dataSource; @NotNull private SQLFactory sqlFactory; @NotEmpty private String tableName = "doc_store"; @NotEmpty private String idColumnName = "id"; @NotEmpty private String updColumnName = "updated"; private int idMaxLength = 256; @NotNull private SubPipeline deletePipeline = new BaseSubPipeline(); @NotEmpty private String idFieldName; private boolean lifecycleSubPipeline = true; /** * Sets {@link Document#setOperation(String)} to either {@link DocumentOperation#ADD_VALUE} or * {@link DocumentOperation#MODIFY_VALUE} based on the outcome of * {@link IdStateHolder#isUpdate(String) idStateHolder.isUpdate(id)}. * * @param doc the document to check. * * @return {@link PipelineStepStatus#DEFAULT}. * * @throws PipelineException if {@link Document#getFieldValue(String) doc.getFieldValue(idFieldName)} * <tt>== null</tt>. */ @Override public PipelineStepStatus execute(Document doc) throws PipelineException { final String id = doc.getFieldValue(idFieldName); if (id == null) { throw new PipelineException("idFieldName '" + idFieldName + "' is null"); } if (idStateHolder.isUpdate(id)) { doc.setOperation(DocumentOperation.MODIFY_VALUE); } else { doc.setOperation(DocumentOperation.ADD_VALUE); } return PipelineStepStatus.DEFAULT; } @Override public void prepare() throws PipelineException { super.prepare(); if (lifecycleSubPipeline) { deletePipeline.prepare(); } if (idStateHolder == null) { idStateHolder = new IdStateHolder(dataSource, sqlFactory, this); } idStateHolder.prepare(); } /** * If <tt>success == true</tt> {@link #getDeletePipeline()}<tt>.execute()</tt> will be called for each document id * that found to be deleted and finally {@link IdStateHolder#commit()}. <br/> * {@link IdStateHolder#rollback()} is called if <tt>success == false</tt>. <br/> * {@link #getDeletePipeline() deletePipeline}<tt>.finish(success)</tt> is called if * {@link #isLifecycleSubPipeline()} <tt>== true</tt>. * * @param success {@inheritDoc} * * @see IdStateHolder#findDeletedIds() */ @Override public void finish(boolean success) throws PipelineException { if (idStateHolder != null) { if (success) { executeDeletePipeline(); idStateHolder.commit(); } else { idStateHolder.rollback(); } } if (lifecycleSubPipeline) { deletePipeline.finish(success); } } private void executeDeletePipeline() throws PipelineException { final Iterator<String> it = idStateHolder.findDeletedIds(); while (it.hasNext()) { final Document doc = new Document(); doc.setFieldValue(idFieldName, it.next()); doc.setOperation(DocumentOperation.DELETE_VALUE); deletePipeline.executeSteps(doc); } } @Override public String getRevision() { return "$Revision$"; } /** * Gets the datasource used for tracking document ids. * * @return the datasource used for tracking document ids. */ public DataSource getDataSource() { return dataSource; } /** * Sets the datasource used for tracking document ids. * * @param dataSource the datasource used for tracking document ids. <em>Cannot</em> be <tt>null</tt>. */ public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } /** * Gets the sql factory used to create the SQL needed. * * @return the sql factory used to create the SQL needed. */ public SQLFactory getSqlFactory() { return sqlFactory; } /** * Sets the sql factory used to create the SQL needed. * * @param sqlFactory the sql factory used to create the SQL needed. <em>Cannot</em> be <tt>null</tt>. */ public void setSqlFactory(SQLFactory sqlFactory) { this.sqlFactory = sqlFactory; } /** * {@inheritDoc} * Default value is <tt>"doc_store"</tt>. */ @Override public String getTableName() { return tableName; } /** * Sets the name of the table. * * @param tableName the name of the table. <em>Cannot</em> be <tt>null</tt> or <tt>""</tt>. */ public void setTableName(String tableName) { this.tableName = tableName; } /** * {@inheritDoc} * Default value is <tt>"id"</tt>. */ @Override public String getIdColumnName() { return idColumnName; } /** * Sets the name of the <tt>ID</tt> column. * * @param idColumnName the name of the <tt>ID</tt> column. <em>Cannot</em> be <tt>null</tt> or <tt>""</tt>. */ public void setIdColumnName(String idColumnName) { this.idColumnName = idColumnName; } /** * {@inheritDoc} * Default value is <tt>"updated"</tt>. */ @Override public String getUpdColumnName() { return updColumnName; } /** * Sets the name of the <tt>lastUpdated</tt> column. * * @param updColumnName the name of the <tt>lastUpdated</tt> column. <em>Cannot</em> be <tt>null</tt> or * <tt>""</tt>. */ public void setUpdColumnName(String updColumnName) { this.updColumnName = updColumnName; } /** * {@inheritDoc} * Default value is <tt>256</tt>. */ @Override public int getIdMaxLength() { return idMaxLength; } public void setIdMaxLength(int idMaxLength) { this.idMaxLength = idMaxLength; } /** * Gets the pipeline to execute for deleted documents. * * @return the pipeline to execute for deleted documents. */ public SubPipeline getDeletePipeline() { return deletePipeline; } /** * Sets the pipeline to execute for deleted documents. * * @param deletePipeline the pipeline to execute for deleted documents. <em>Cannot</em> be <tt>null</tt>. */ public void setDeletePipeline(SubPipeline deletePipeline) { this.deletePipeline = deletePipeline; } /** * Get in what field of the document the id can be found. * * @return the name of the id-field. */ public String getIdFieldName() { return idFieldName; } /** * Set in what field of the document the id can be found. * * @param idFieldName the name of the id-field. <em>Cannot</em> be <tt>null</tt> or <tt>""</tt>. */ public void setIdFieldName(String idFieldName) { this.idFieldName = idFieldName; } /** * Gets whether to call <tt>prepare()</tt> and <tt>finish()</tt> on {@link #getDeletePipeline() deletePipeline}. * Default value is <tt>true</tt>. * * @return <tt>true</tt> if <tt>prepare()</tt> and <tt>finish()</tt> should be called on * {@link #getDeletePipeline() deletePipeline}. */ public boolean isLifecycleSubPipeline() { return lifecycleSubPipeline; } /** * Sets whether to call <tt>prepare()</tt> and <tt>finish()</tt> on {@link #getDeletePipeline() deletePipeline}. * * @param lifecycleSubPipeline set to <tt>true</tt> if <tt>prepare()</tt> and <tt>finish()</tt> should be called on * {@link #getDeletePipeline() deletePipeline}. * * @see #isLifecycleSubPipeline() */ public void setLifecycleSubPipeline(boolean lifecycleSubPipeline) { this.lifecycleSubPipeline = lifecycleSubPipeline; } }