A data source in Java is the means of retrieving a connection to a database. A data source object will be registered with a naming service based on the Java Naming and Directory Interface (JNDI) API. Thus, to acquire a connection to the database, an Appian plug-in must obtain a JNDI data source connection.
This document shows the best practices for obtaining a JNDI data source connection from within a custom Appian plug-in. In all the examples a javax.naming.Context must be acquired to retrieve a connection.
Before getting started, the JNDI name of a data source must already be known. The easiest way to retrieve this for an existing data source is through the Data Sources drop down on the Data Stores tab.
Once a connection has been retrieved it must be closed when finished to ensure the pool is not starved of available connections. An application server or JDBC driver may attempt to close dangling connections automatically but that should not be relied upon.
Java 7 offers a convenient try-with-resources syntax to automatically close a resource when the code block completes normally or abruptly by exception. This syntax is cleaner than traditional code that uses a finally block to close connections.
finally
try (Connection conn = ds.getConnection()) { try (PreparedStatement ps = conn.prepareStatement("SELECT name FROM customer")) { ResultSet rs = ps.executeQuery(); while (rs.next()) { String name = rs.getString("name"); } } }
Notes
javax.naming.Context
new InitialContext()
Example
@Function public String getCustomerNameById( ServiceContext sc, Context ctx, @Parameter long id ) throws NamingException, SQLException { DataSource ds = (DataSource) ctx.lookup("jdbc/AppianBusinessDS"); String name = null; try (Connection conn = ds.getConnection()) { try (PreparedStatement ps = conn.prepareStatement("SELECT name FROM customer WHERE id = ?")) { ps.setLong(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { name = rs.getString("name"); } } } return name; }
@ConnectivityServices public class UpdateCustomerName extends AppianSmartService { private SmartServiceContext smartServiceCtx; private Context ctx; private Long id; private String name; public UpdateCustomerName(SmartServiceContext smartServiceCtx, Context ctx) { this.smartServiceCtx = smartServiceCtx; this.ctx = ctx; } @Override public void run() throws SmartServiceException { try { updateCustomerName(); } catch (NamingException | SQLException e) { throw new SmartServiceException.Builder(UpdateCustomerName.class, e).build(); } } public void updateCustomerName() throws NamingException, SQLException { DataSource ds = (DataSource) ctx.lookup("jdbc/AppianBusinessDS"); try (Connection conn = ds.getConnection()) { try (CallableStatement call = conn.prepareCall("{ call update_customer_name(?, ?) }")) { call.setLong(1, id); call.setString(2, name); call.execute(); } } } @Input(required = Required.ALWAYS) @Name("CustomerId") public void setCustomerId(Long val) { this.id = val; } @Input(required = Required.ALWAYS) @Name("NewCustomerName") public void setNewCustomerName(String val) { this.name = val; } }
This example is a simple servlet that connects to a JNDI data source provided by the application server, executes an SQL query and iterates through the results.
Use Cases:
Non Use Cases
public class DatabaseServlet extends HttpServlet { @Override protected void doGet( Context ctx, HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { PrintWriter pw = new PrintWriter(resp.getOutputStream()); long id = Long.parseLong(req.getParameter("id")); String name = null; try { DataSource ds = (DataSource) ctx.lookup("jdbc/AppianBusinessDS"); try (Connection conn = ds.getConnection()) { try (PreparedStatement ps = conn.prepareStatement("SELECT name FROM customer WHERE id = ?")) { ps.setLong(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { name = rs.getString("name"); } } } } catch (Exception e) { throw new ServletException("An error occurred while processing the GET request", e); } if (name == null) { pw.write("No customer found."); } else { pw.write("Customer Name: " + name); } } }