001/*
002 * Copyright 2002-2018 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;
020
021import javax.resource.ResourceException;
022import javax.resource.cci.ConnectionFactory;
023import javax.resource.cci.InteractionSpec;
024import javax.resource.cci.Record;
025import javax.resource.cci.RecordFactory;
026
027import org.springframework.dao.DataAccessException;
028import org.springframework.jca.cci.core.RecordCreator;
029import org.springframework.jca.cci.core.RecordExtractor;
030import org.springframework.lang.Nullable;
031import org.springframework.util.Assert;
032
033/**
034 * EIS operation object that expects mapped input and output objects,
035 * converting to and from CCI Records.
036 *
037 * <p>Concrete subclasses must implement the abstract
038 * {@code createInputRecord(RecordFactory, Object)} and
039 * {@code extractOutputData(Record)} methods, to create an input
040 * Record from an object and to convert an output Record into an object,
041 * respectively.
042 *
043 * @author Thierry Templier
044 * @author Juergen Hoeller
045 * @since 1.2
046 * @see #createInputRecord(javax.resource.cci.RecordFactory, Object)
047 * @see #extractOutputData(javax.resource.cci.Record)
048 */
049public abstract class MappingRecordOperation extends EisOperation {
050
051        /**
052         * Constructor that allows use as a JavaBean.
053         */
054        public MappingRecordOperation() {
055        }
056
057        /**
058         * Convenient constructor with ConnectionFactory and specifications
059         * (connection and interaction).
060         * @param connectionFactory the ConnectionFactory to use to obtain connections
061         */
062        public MappingRecordOperation(ConnectionFactory connectionFactory, InteractionSpec interactionSpec) {
063                getCciTemplate().setConnectionFactory(connectionFactory);
064                setInteractionSpec(interactionSpec);
065        }
066
067        /**
068         * Set a RecordCreator that should be used for creating default output Records.
069         * <p>Default is none: CCI's {@code Interaction.execute} variant
070         * that returns an output Record will be called.
071         * <p>Specify a RecordCreator here if you always need to call CCI's
072         * {@code Interaction.execute} variant with a passed-in output Record.
073         * This RecordCreator will then be invoked to create a default output Record instance.
074         * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record)
075         * @see javax.resource.cci.Interaction#execute(javax.resource.cci.InteractionSpec, Record, Record)
076         * @see org.springframework.jca.cci.core.CciTemplate#setOutputRecordCreator
077         */
078        public void setOutputRecordCreator(RecordCreator creator) {
079                getCciTemplate().setOutputRecordCreator(creator);
080        }
081
082        /**
083         * Execute the interaction encapsulated by this operation object.
084         * @param inputObject the input data, to be converted to a Record
085         * by the {@code createInputRecord} method
086         * @return the output data extracted with the {@code extractOutputData} method
087         * @throws DataAccessException if there is any problem
088         * @see #createInputRecord
089         * @see #extractOutputData
090         */
091        @Nullable
092        public Object execute(Object inputObject) throws DataAccessException {
093                InteractionSpec interactionSpec = getInteractionSpec();
094                Assert.state(interactionSpec != null, "No InteractionSpec set");
095                return getCciTemplate().execute(
096                                interactionSpec, new RecordCreatorImpl(inputObject), new RecordExtractorImpl());
097        }
098
099
100        /**
101         * Subclasses must implement this method to generate an input Record
102         * from an input object passed into the {@code execute} method.
103         * @param inputObject the passed-in input object
104         * @return the CCI input Record
105         * @throws ResourceException if thrown by a CCI method, to be auto-converted
106         * to a DataAccessException
107         * @see #execute(Object)
108         */
109        protected abstract Record createInputRecord(RecordFactory recordFactory, Object inputObject)
110                        throws ResourceException, DataAccessException;
111
112        /**
113         * Subclasses must implement this method to convert the Record returned
114         * by CCI execution into a result object for the {@code execute} method.
115         * @param outputRecord the Record returned by CCI execution
116         * @return the result object
117         * @throws ResourceException if thrown by a CCI method, to be auto-converted
118         * to a DataAccessException
119         * @see #execute(Object)
120         */
121        protected abstract Object extractOutputData(Record outputRecord)
122                        throws ResourceException, SQLException, DataAccessException;
123
124
125        /**
126         * Implementation of RecordCreator that calls the enclosing
127         * class's {@code createInputRecord} method.
128         */
129        protected class RecordCreatorImpl implements RecordCreator {
130
131                private final Object inputObject;
132
133                public RecordCreatorImpl(Object inObject) {
134                        this.inputObject = inObject;
135                }
136
137                @Override
138                public Record createRecord(RecordFactory recordFactory) throws ResourceException, DataAccessException {
139                        return createInputRecord(recordFactory, this.inputObject);
140                }
141        }
142
143
144        /**
145         * Implementation of RecordExtractor that calls the enclosing
146         * class's {@code extractOutputData} method.
147         */
148        protected class RecordExtractorImpl implements RecordExtractor<Object> {
149
150                @Override
151                public Object extractData(Record record) throws ResourceException, SQLException, DataAccessException {
152                        return extractOutputData(record);
153                }
154        }
155
156}