/**
* i-net software provides programming examples for illustration only, without warranty
* either expressed or implied, including, but not limited to, the implied warranties
* of merchantability and/or fitness for a particular purpose. This programming example
* assumes that you are familiar with the programming language being demonstrated and
* the tools used to create and debug procedures. i-net software support professionals
* can help explain the functionality of a particular procedure, but they will not modify
* these examples to provide added functionality or construct procedures to meet your
* specific needs.
*
* Copyright © 1999-2026 i-net software GmbH, Berlin, Germany.
**/
package com.inet.taskplanner.databaseaction;
import static com.inet.taskplanner.databaseaction.TaskPlannerDatabaseActionServerPlugin.MSG;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.inet.config.structure.model.LocalizedKey;
import com.inet.id.GUID;
import com.inet.plugin.ServerPluginManager;
import com.inet.taskplanner.server.api.action.ResultActionDefinition;
import com.inet.taskplanner.server.api.action.ResultActionFactory;
import com.inet.taskplanner.server.api.action.ResultActionInfo;
import com.inet.taskplanner.server.api.common.SummaryEntry;
import com.inet.taskplanner.server.api.common.SummaryInfo;
import com.inet.taskplanner.server.api.error.ValidationException;
import com.inet.taskplanner.server.api.field.Field;
import com.inet.taskplanner.server.api.field.SelectField;
import com.inet.taskplanner.server.api.field.TextField;
import com.inet.taskplanner.server.api.result.ResultFlavor;
import com.inet.taskplanner.server.api.series.db.DataSourceProvider;
/**
* A result action factory defines how the action is presented to the user and may include validation of user-configurable properties.
*
* This factory produces actions that allow saving files into the configured database, using the configured Data Source.
*/
public class DataSourceDatabaseResultActionFactory extends ResultActionFactory {
/**
* Key of the data source property.
*/
public static final String DATASOURCE = "datasource";
/**
* Key of the table property.
*/
public static final String TABLE = "table";
/**
* Key of the file column property.
*/
public static final String FILE_COLUMN = "filecolumn";
/**
* Key of the optional identifier column property.
*/
public static final String IDENTIFIER_COLUMN = "identifiercolumn";
/**
* Key of the value property for identifier column. Type of value may be long or string.
*/
public static final String IDENTIFIER_VALUE = "identifiervalue";
/**
* Creates instance of the factory.
*/
public DataSourceDatabaseResultActionFactory() {
super( "action.database.datasource" );
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAvailable() {
// Action is available only if provider of connections to data sources is available
return getOptionalDataSourceProvider() != null;
}
/** Returns data source provider or null, if it is not available.
* @return data source provider or null, if it is not available.
*/
private DataSourceProvider getOptionalDataSourceProvider() {
return ServerPluginManager.getInstance().getOptionalInstance( DataSourceProvider.class );
}
/**
* {@inheritDoc}
*/
@Override
public List getSupportedFlavors( ResultActionDefinition definition ) {
// Actions produced by this factory are interested in file results
return Arrays.asList( ResultFlavor.FILE );
}
/**
* {@inheritDoc}
*/
@Override
public ResultActionInfo getInformation( @Nullable GUID taskID ) {
String name = MSG.getMsg( "taskplanner.databaseaction.name.datasource" ); // A meaningful name
String description = MSG.getMsg( "taskplanner.databaseaction.description.datasource" ); // A short description
URL icon = getClass().getResource( "/com/inet/taskplanner/databaseaction/taskplanner_databaseaction_32.png" ); // white and transparent icon in 32x32 pixels
String helpkey = null; // The result action does not have its own help page
List fields = new ArrayList(); // Fields displayed for configuration. Use null if no configuration is required.
// Creates list with available data sources
List dataSourceNames = getOptionalDataSourceProvider().getDataSourceNames();
if( !dataSourceNames.isEmpty() ) {
Collections.sort( dataSourceNames );
ArrayList values = new ArrayList<>();
for( String dataSourceName : dataSourceNames ) {
values.add( new LocalizedKey( dataSourceName, dataSourceName ) );
}
SelectField selectField = new SelectField( DATASOURCE, MSG.getMsg( "taskplanner.databaseaction.datasource" ), values );
selectField.setValue( values.get( 0 ).getKey() );
fields.add( selectField );
}
fields.add( new TextField( TABLE, MSG.getMsg( "taskplanner.databaseaction.table" ) ) );
fields.add( new TextField( FILE_COLUMN, MSG.getMsg( "taskplanner.databaseaction.filecolumn" ) ) );
TextField identifierColumnField = new TextField( IDENTIFIER_COLUMN, MSG.getMsg( "taskplanner.databaseaction.identifiercolumn" ) );
identifierColumnField.setPlaceholder( MSG.getMsg( "taskplanner.databaseaction.placeholder.optional" ) );
fields.add( identifierColumnField );
TextField identifierValueField = new TextField( IDENTIFIER_VALUE, MSG.getMsg( "taskplanner.databaseaction.identifiervalue" ) );
identifierValueField.setPlaceholder( MSG.getMsg( "taskplanner.databaseaction.placeholder.optional" ) );
fields.add( identifierValueField );
return new ResultActionInfo( getExtensionName(), name, description, icon, helpkey, fields );
}
/**
* {@inheritDoc}
*/
@Override
protected void validate( @Nonnull ResultActionDefinition definition, @Nullable GUID taskID ) throws ValidationException {
String datasource = definition.getProperty( DATASOURCE );
String table = definition.getProperty( TABLE );
String fileColumn = definition.getProperty( FILE_COLUMN );
// Checks whether data source, table and column names are provided
if( datasource == null || datasource.trim().isEmpty() ) {
throw new ValidationException( MSG.getMsg( "taskplanner.databaseaction.datasource.empty" ) );
}
if( table == null || table.trim().isEmpty() ) {
throw new ValidationException( MSG.getMsg( "taskplanner.databaseaction.table.empty" ) );
}
if( fileColumn == null || fileColumn.trim().isEmpty() ) {
throw new ValidationException( MSG.getMsg( "taskplanner.databaseaction.filecolumn.empty" ) );
}
// Checks whether connection to the database is possible and whether configured table exists
String sql = "SELECT COUNT(*) FROM " + table;
try (Connection con = getOptionalDataSourceProvider().getConnection( datasource ); Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery( sql )) {
if( rs.next() ) {
rs.getInt( 1 );
}
} catch( Exception ex ) {
throw new ValidationException( ex.getMessage() );
}
}
/**
* {@inheritDoc}
*/
@Override
protected DataSourceDatabaseResultAction createInstanceFrom( @Nonnull ResultActionDefinition definition ) {
String datasource = definition.getProperty( DATASOURCE );
String table = definition.getProperty( TABLE );
String fileColumn = definition.getProperty( FILE_COLUMN );
String identifierColumn = definition.getProperty( IDENTIFIER_COLUMN );
String identifierValue = definition.getProperty( IDENTIFIER_VALUE );
if( identifierColumn == null || identifierColumn.trim().isEmpty() ) {
return new DataSourceDatabaseResultAction( getOptionalDataSourceProvider(), datasource, table, fileColumn );
}
return new DataSourceDatabaseResultAction( getOptionalDataSourceProvider(), datasource, table, fileColumn, identifierColumn, identifierValue );
}
/**
* {@inheritDoc}
*/
@Override
public SummaryInfo getSummary( @Nonnull ResultActionDefinition definition ) {
List result = new ArrayList<>();
result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.datasource" ), definition.getProperty( DATASOURCE ) ) );
result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.table" ), definition.getProperty( TABLE ) ) );
result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.filecolumn" ), definition.getProperty( FILE_COLUMN ) ) );
String identifierColumn = definition.getProperty( IDENTIFIER_COLUMN );
if( identifierColumn != null && !identifierColumn.trim().isEmpty() ) {
result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.identifiercolumn" ), identifierColumn ) );
}
String identifierValue = definition.getProperty( IDENTIFIER_VALUE );
if( identifierValue != null && !identifierValue.trim().isEmpty() ) {
result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.identifiervalue" ), identifierValue ) );
}
return new SummaryInfo( result );
}
}