In this example, an operation is created that connects to a relational database and executes an SQL statement. The result should be inserted in the edited XML document as a table. To make the operation fully configurable, it will have arguments for the database connection string, the user name, the password and the SQL expression.
simple.documentation.framework.QueryDatabaseOperation. This class must
implement the ro.sync.ecss.extensions.api.AuthorOperation
interface.
import ro.sync.ecss.extensions.api.ArgumentDescriptor;
import ro.sync.ecss.extensions.api.ArgumentsMap;
import ro.sync.ecss.extensions.api.AuthorAccess;
import ro.sync.ecss.extensions.api.AuthorOperation;
import ro.sync.ecss.extensions.api.AuthorOperationException;
public class QueryDatabaseOperation implements AuthorOperation{
String constant representing the argument name:
private static final String ARG_JDBC_DRIVER ="jdbc_driver";
private static final String ARG_USER ="user";
private static final String ARG_PASSWORD ="password";
private static final String ARG_SQL ="sql";
private static final String ARG_CONNECTION ="connection";
getArguments method that will return an array of argument
descriptors:
public ArgumentDescriptor[] getArguments() {
ArgumentDescriptor args[] = new ArgumentDescriptor[] {
new ArgumentDescriptor(
ARG_JDBC_DRIVER,
ArgumentDescriptor.TYPE_STRING,
"The name of the Java class that is the JDBC driver."),
new ArgumentDescriptor(
ARG_CONNECTION,
ArgumentDescriptor.TYPE_STRING,
"The database URL connection string."),
new ArgumentDescriptor(
ARG_USER,
ArgumentDescriptor.TYPE_STRING,
"The name of the database user."),
new ArgumentDescriptor(
ARG_PASSWORD,
ArgumentDescriptor.TYPE_STRING,
"The database password."),
new ArgumentDescriptor(
ARG_SQL,
ArgumentDescriptor.TYPE_STRING,
"The SQL statement to be executed.")
};
return args;
}
These names, types and descriptions will be listed in the Arguments table when the operation is configured.
doOperation
method extracts the arguments, forwards them to the method that connects to the database
and generates the XML fragment. The XML fragment is then inserted at the cursor
position.
public void doOperation(AuthorAccess authorAccess, ArgumentsMap map)
throws IllegalArgumentException, AuthorOperationException {
// Collects the arguments.
String jdbcDriver = (String)map.getArgumentValue(ARG_JDBC_DRIVER);
String connection = (String)map.getArgumentValue(ARG_CONNECTION);
String user = (String)map.getArgumentValue(ARG_USER);
String password = (String)map.getArgumentValue(ARG_PASSWORD);
String sql = (String)map.getArgumentValue(ARG_SQL);
int caretPosition = authorAccess.getCaretOffset();
try {
authorAccess.getDocumentController().insertXMLFragment(
getFragment(jdbcDriver, connection, user, password, sql), caretPosition);
} catch (SQLException e) {
throw new AuthorOperationException(
"The operation failed due to the following database error: "
+ e.getMessage(), e);
} catch (ClassNotFoundException e) {
throw new AuthorOperationException(
"The JDBC database driver was not found. Tried to load ' "
+ jdbcDriver + "'", e);
}
}
getFragment method loads the JDBC driver, connects to the database
and extracts the data. The result is a <table> element from the
http://www.oxygenxml.com/sample/documentation namespace. The
<header> element contains the names of the SQL columns. All the
text from the XML fragment is escaped. This means that the '<' and '&' characters
are replaced with the '<' and '&' character entities to ensure that the
fragment is well-formed.
private String getFragment(String jdbcDriver, String connectionURL, String user,
String password, String sql) throws SQLException, ClassNotFoundException {
Properties pr = new Properties();
pr.put("characterEncoding", "UTF8");
pr.put("useUnicode", "TRUE");
pr.put("user", user);
pr.put("password", password);
// Loads the database driver.
Class.forName(jdbcDriver);
// Opens the connection
Connection connection = DriverManager.getConnection(connectionURL, pr);
java.sql.Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
StringBuffer fragmentBuffer = new StringBuffer();
fragmentBuffer.append(
"<table xmlns=" +
"'http://www.oxygenxml.com/sample/documentation'>");
//
// Creates the table header.
//
fragmentBuffer.append("<header>");
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
fragmentBuffer.append("<td>");
fragmentBuffer.append(xmlEscape(metaData.getColumnName(i)));
fragmentBuffer.append("</td>");
}
fragmentBuffer.append("</header>");
//
// Creates the table content.
//
while (resultSet.next()) {
fragmentBuffer.append("<tr>");
for (int i = 1; i <= columnCount; i++) {
fragmentBuffer.append("<td>");
fragmentBuffer.append(xmlEscape(resultSet.getObject(i)));
fragmentBuffer.append("</td>");
}
fragmentBuffer.append("</tr>");
}
fragmentBuffer.append("</table>");
// Cleanup
resultSet.close();
statement.close();
connection.close();
return fragmentBuffer.toString();
}
Add button. In the
displayed dialog box, enter the location of the JAR file, relative to the Oxygen XML Author Eclipse plugin
frameworks folder.
local-name()='section'Use the Java operation defined earlier to set the Invoke
operation field. Click the Choose button, then select
simple.documentation.framework.QueryDatabaseOperation. Once
selected, the list of arguments is displayed. In the figure below the first
argument, jdbc_driver, represents the class name of the MySQL JDBC driver.
The connection string has the URL syntax:
jdbc://<database_host>:<database_port>/<database_name>.
SELECT userID, email FROM users
To test the action, open or create an XML file and place the cursor at a valid location.
Then click the
Create
Report button from the toolbar. You can see below the toolbar with the action
button and sample table inserted by the Clients Report action.