Статьи

Простой транзакционный файл JCA 1.5 Connector

Существует распространенное предубеждение, что разъемы 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