Существует распространенное предубеждение, что разъемы JCA должны быть слишком сложными для повседневного использования. Вместо этого создаются «нестандартные и легковесные» решения, которые обычно на несколько порядков сложнее, чем прагматичная реализация JCA. Итак, вот как это сделать:
- Соединители JCA развернуты как архивы .rar с внутренней структурой, аналогичной архивам ejb-jar. Вы можете повторно использовать существующую упаковку и просто изменить окончание с .jar на .rar
- Начните с дескриптора развертывания ra.xml. Вы «только» должны реализовать элементы, перечисленные в этом дескрипторе развертывания:
<connector xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd" version="1.5"> <display-name>Generic JCA</display-name> <vendor-name>adam-bien.com</vendor-name> <eis-type>Generic JCA</eis-type> <resourceadapter-version>1.0</resourceadapter-version> <resourceadapter> <outbound-resourceadapter> <connection-definition> <managedconnectionfactory-class>...genericjca.GenericManagedConnectionFactory</managedconnectionfactory-class> <connectionfactory-interface>...genericjca.DataSource</connectionfactory-interface> <connectionfactory-impl-class>...genericjca.FileDataSource</connectionfactory-impl-class> <connection-interface>...genericjca.Connection</connection-interface> <connection-impl-class>...genericjca.FileConnection</connection-impl-class> </connection-definition> <transaction-support>LocalTransaction</transaction-support> <authentication-mechanism> <authentication-mechanism-type>BasicPassword</authentication-mechanism-type> <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface> </authentication-mechanism> <reauthentication-support>false</reauthentication-support> </outbound-resourceadapter> </resourceadapter>
</connector>
- GenericManagedConnectionFactory и GenericManagedConnection в основном можно использовать повторно. Эти классы заботятся об управлении соединением. Вы сможете управлять соединителем, например, через консоль администратора Glassfish. Код на удивление прост — в основном ведение бухгалтерского учета и ведение журнала. См http://kenai.com/projects/javaee-patterns/ , проецировать GenericJCA.
- «Основная» бизнес-логика находится в FileConnection:
public class FileConnection implements Connection, LocalTransaction{ private String buffer; private FileOutputStream fileOutputStream; private ConnectionRequestInfo connectionRequestInfo; public final static String FILE_NAME = "/temp/jcafile.txt"; private GenericManagedConnection genericManagedConnection; private PrintWriter out; public FileConnection(PrintWriter out,GenericManagedConnection genericManagedConnection,ConnectionRequestInfo connectionRequestInfo) { this.out = out; this.genericManagedConnection = genericManagedConnection; this.connectionRequestInfo = connectionRequestInfo; this.initialize(); } private void initialize(){ try { this.buffer = null; this.fileOutputStream = new FileOutputStream(FILE_NAME,true); } catch (FileNotFoundException ex) { Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex); throw new IllegalStateException("Cannot initialize OutputStream: " + FILE_NAME); } } public void write(String content) { this.buffer = content; } public void close() { this.genericManagedConnection.close(); } public void destroy(){ try { if(this.fileOutputStream != null) this.fileOutputStream.close(); this.fileOutputStream = null; this.buffer = null; } catch (IOException ex) { Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex); throw new IllegalStateException("Cannot close stream: " +ex,ex); } } public void begin() throws ResourceException { this.initialize(); } public void commit() throws ResourceException { out.println("#FileConnection.commit " +toString()); try { this.fileOutputStream.write(this.buffer.getBytes()); this.fileOutputStream.flush(); this.fileOutputStream.close(); } catch (IOException ex) { Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex); throw new ResourceException(ex); } } public void rollback() throws ResourceException { out.println("#FileConnection.rollback " +toString()); this.buffer = null; try { this.fileOutputStream.close(); } catch (IOException ex) { Logger.getLogger(FileConnection.class.getName()).log(Level.SEVERE, null, ex); throw new ResourceException(ex); }
Приятной вещью являются обратные вызовы транзакций. Контейнер уведомит вас о ходе транзакции. Во время фиксации вы просто записываете буфер в файл — в случае отката вы должны очистить буфер. Этот пример не является полностью транзакционным — поскольку в целом вам придется иметь дело с поврежденными файлами и т. Д. — но должно быть ясно, как он работает.
После установки вы сможете внедрить интерфейс (и, следовательно, FileConnection ) в свою бизнес-логику.
@Stateless public class JCAClientBean implements JCAClientRemote { @Resource(mappedName="jca/FileFactory") private DataSource dataSource;
… и транзакции будут распространяться прозрачно для вас.
Разъемы JCA не так просты, как EJB 3.1 или CDI, но на несколько порядков более надежны и удобнее в обслуживании, чем решения и обходные пути, которые обычно создаются вместо этого.
Вы найдете рабочий пример (протестированный с Glassfish v2) по адресу http://kenai.com/projects/javaee-patterns/ . См. Проекты GenericJCA, GenericJCAAPI и JCAClient. Я описал это решение в отдельной главе «Универсальная JCA», стр. 181 в Реальном мире Шаблоны Java EE — Переосмысление передового опыта » .
Представленный здесь пример основан на древней технологии Java EE 5. Разъемы JCA 1.6 намного проще и элегантнее — следите за обновлениями.
От http://www.adam-bien.com/roller/abien/entry/a_simple_transactional_file_jca