/** * 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.io.IOException; import java.net.URL; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.inet.id.GUID; import com.inet.taskplanner.TaskPlannerServerPlugin; 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.PasswordField; import com.inet.taskplanner.server.api.field.TextField; import com.inet.taskplanner.server.api.result.ResultFlavor; /** * 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 JDBC URL for connection. */ public class JdbcDatabaseResultActionFactory extends ResultActionFactory { /** * Key of the JDBC URL property. */ public static final String JDBC_URL = "url"; /** * Key of the user name property. */ public static final String USERNAME = "username"; /** * Key of the password property. */ public static final String PASSWORD = "password"; /** * 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 JdbcDatabaseResultActionFactory() { super( "action.database.jdbc" ); } /** * {@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.jdbc" ); // A meaningful name String description = MSG.getMsg( "taskplanner.databaseaction.description.jdbc" ); // 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. fields.add( new TextField( JDBC_URL, MSG.getMsg( "taskplanner.databaseaction.jdbcurl" ) ) ); fields.add( new TextField( USERNAME, MSG.getMsg( "taskplanner.databaseaction.username" ) ) ); fields.add( new PasswordField( PASSWORD, MSG.getMsg( "taskplanner.databaseaction.password" ) ) ); 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 jdbcURL = definition.getProperty( JDBC_URL ); String username = definition.getProperty( USERNAME ); String decodedPassword = decodePassword( definition.getProperty( PASSWORD ) ); String table = definition.getProperty( TABLE ); String fileColumn = definition.getProperty( FILE_COLUMN ); // Checks whether table and column names are provided (other settings will be verified when attempting to establish connection) 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 = DriverManager.getConnection( jdbcURL, username, decodedPassword ); 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 JdbcDatabaseResultAction createInstanceFrom( @Nonnull ResultActionDefinition definition ) { String jdbcURL = definition.getProperty( JDBC_URL ); String username = definition.getProperty( USERNAME ); String decodedPassword = decodePassword( definition.getProperty( PASSWORD ) ); 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 JdbcDatabaseResultAction( jdbcURL, username, decodedPassword, table, fileColumn ); } return new JdbcDatabaseResultAction( jdbcURL, username, decodedPassword, table, fileColumn, identifierColumn, identifierValue ); } /** * {@inheritDoc} */ @Override public SummaryInfo getSummary( @Nonnull ResultActionDefinition definition ) { List result = new ArrayList<>(); result.add( new SummaryEntry( MSG.getMsg( "taskplanner.databaseaction.jdbcurl" ), definition.getProperty( JDBC_URL ) ) ); 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 ); } /** Decodes password, if provided. * @param password password to decode. * @return decoded password. */ private String decodePassword( String password ) { if( password != null && !password.isEmpty() ) { try { password = PasswordField.decodePassword( password ); } catch( IOException ex ) { TaskPlannerServerPlugin.LOGGER.error( ex ); } } return password; } }