001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jca.cci.object;
018
019import java.sql.SQLException;
020import javax.resource.ResourceException;
021import javax.resource.cci.ConnectionFactory;
022import javax.resource.cci.InteractionSpec;
023import javax.resource.cci.Record;
024import javax.resource.cci.RecordFactory;
025
026import org.springframework.dao.DataAccessException;
027import org.springframework.jca.cci.core.RecordCreator;
028import org.springframework.jca.cci.core.RecordExtractor;
029
030/**
031 * EIS operation object that expects mapped input and output objects,
032 * converting to and from CCI Records.
033 *
034 * <p>Concrete subclasses must implement the abstract
035 * {@code createInputRecord(RecordFactory, Object)} and
036 * {@code extractOutputData(Record)} methods, to create an input
037 * Record from an object and to convert an output Record into an object,
038 * respectively.
039 *
040 * @author Thierry Templier
041 * @author Juergen Hoeller
042 * @since 1.2
043 * @see #createInputRecord(javax.resource.cci.RecordFactory, Object)
044 * @see #extractOutputData(javax.resource.cci.Record)
045 */
046public abstract class MappingRecordOperation extends EisOperation {
047
048        /**
049         * Constructor that allows use as a JavaBean.
050         */
051        public MappingRecordOperation() {
052        }
053
054        /**
055         * Convenient constructor with ConnectionFactory and specifications
056         * (connection and interaction).
057         * @param connectionFactory ConnectionFactory to use to obtain connections
058         */
059        public MappingRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
060                getCciTemplate().setConnectionFactory(connectionFactory);
061                setInteractionSpec(interactionSpec);
062        }
063
064        /**
065         * Set a RecordCreator that should be used for creating default output Records.
066         * <p>Default is none: CCI's {@code Interaction.execute} variant
067         * that returns an output Record will be called.
068         * <p>Specify a RecordCreator here if you always need to call CCI's
069         * {@code Interaction.execute} variant with a passed-in output Record.
070         * This RecordCreator will then be invoked to create a default output Record instance.
071         * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
072         * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
073         * @see org.springframework.jca.cci.core.CciTemplate#setOutputRecordCreator
074         */
075        public void setOutputRecordCreator(RecordCreator creator) {
076                getCciTemplate().setOutputRecordCreator(creator);
077        }
078
079        /**
080         * Execute the interaction encapsulated by this operation object.
081         * @param inputObject the input data, to be converted to a Record
082         * by the {@code createInputRecord} method
083         * @return the output data extracted with the {@code extractOutputData} method
084         * @throws DataAccessException if there is any problem
085         * @see #createInputRecord
086         * @see #extractOutputData
087         */
088        public Object execute(Object inputObject) throws DataAccessException {
089                return getCciTemplate().execute(
090                                getInteractionSpec(), new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
091        }
092
093
094        /**
095         * Subclasses must implement this method to generate an input Record
096         * from an input object passed into the {@code execute} method.
097         * @param inputObject the passed-in input object
098         * @return the CCI input Record
099         * @throws ResourceException if thrown by a CCI method, to be auto-converted
100         * to a DataAccessException
101         * @see #execute(Object)
102         */
103        protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
104                        throws ResourceException, DataAccessException;
105
106        /**
107         * Subclasses must implement this method to convert the Record returned
108         * by CCI execution into a result object for the {@code execute} method.
109         * @param outputRecord the Record returned by CCI execution
110         * @return the result object
111         * @throws ResourceException if thrown by a CCI method, to be auto-converted
112         * to a DataAccessException
113         * @see #execute(Object)
114         */
115        protected abstract Object extractOutputData(Record outputRecord)
116                        throws ResourceException, SQLException, DataAccessException;
117
118
119        /**
120         * Implementation of RecordCreator that calls the enclosing
121         * class's {@code createInputRecord} method.
122         */
123        protected class RecordCreatorImpl implements RecordCreator {
124
125                private final Object inputObject;
126
127                public RecordCreatorImpl(Object inObject) {
128                        this.inputObject = inObject;
129                }
130
131                @Override
132                public Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException {
133                        return createInputRecord(recordFactory, this.inputObject);
134                }
135        }
136
137
138        /**
139         * Implementation of RecordExtractor that calls the enclosing
140         * class's {@code extractOutputData} method.
141         */
142        protected class RecordExtractorImpl implements RecordExtractor<Object> {
143
144                @Override
145                public Object extractData(Record record) throws ResourceException, SQLException, DataAccessException {
146                        return extractOutputData(record);
147                }
148        }
149
150}