001package ca.uhn.hl7v2.hoh.llp;
002
003import java.io.IOException;
004import java.io.InputStream;
005import java.io.OutputStream;
006import java.nio.charset.Charset;
007
008import ca.uhn.hl7v2.app.TwoPortService;
009import ca.uhn.hl7v2.hoh.api.IAuthorizationClientCallback;
010import ca.uhn.hl7v2.hoh.api.IAuthorizationServerCallback;
011import ca.uhn.hl7v2.hoh.sign.ISigner;
012import ca.uhn.hl7v2.hoh.util.ServerRoleEnum;
013import ca.uhn.hl7v2.llp.HL7Reader;
014import ca.uhn.hl7v2.llp.HL7Writer;
015import ca.uhn.hl7v2.llp.LLPException;
016import ca.uhn.hl7v2.llp.LowerLayerProtocol;
017
018/**
019 * <p>
020 * LowerLayerProtocol implementation which use the HL7 over HTTP specification
021 * as a transport layer.
022 * </p>
023 * 
024 * <p>
025 * Note that this implementation has limitations:
026 * <ul>
027 * <li>It will not work on a duel socket server such as {@link TwoPortService}
028 * </ul>
029 * </p>
030 */
031public class Hl7OverHttpLowerLayerProtocol extends LowerLayerProtocol {
032
033        private IAuthorizationClientCallback myAuthorizationClientCallback;
034        private IAuthorizationServerCallback myAuthorizationServerCallback;
035        private HohLlpReader myNextReader;
036        private HohLlpWriter myNextWriter;
037        private ServerRoleEnum myRole;
038        private ISigner mySigner;
039        private String myUriPath = "/";
040        private Charset myPreferredCharset;
041        
042        public Hl7OverHttpLowerLayerProtocol(ServerRoleEnum theRole) {
043                myRole = theRole;
044
045                if (myRole == null) {
046                        throw new NullPointerException("Role can not be null");
047                }
048        }
049        /**
050         * @return the authorizationClientCallback
051         */
052        IAuthorizationClientCallback getAuthorizationClientCallback() {
053                return myAuthorizationClientCallback;
054        }
055
056        /**
057         * Provide the authorization callback, if any
058         */
059        IAuthorizationServerCallback getAuthorizationServerCallback() {
060                return myAuthorizationServerCallback;
061        }
062
063        /**
064         * {@inheritDoc}
065         */
066        @Override
067        public HL7Reader getReader(InputStream theArg0) throws LLPException {
068                if (myNextReader == null && myNextWriter != null) {
069                        myNextWriter = null;
070                        throw new LLPException("Hl7OverHttpLowerLayerProtocol can not be used with a multi socket implementation");
071                }
072                prepareReadersIfNeeded();
073                HohLlpReader retVal = myNextReader;
074                try {
075                        retVal.setInputStream(theArg0);
076                } catch (IOException e) {
077                        throw new LLPException("Failed to set stream: " + e.getMessage(), e);
078                }
079
080                myNextReader = null;
081                return retVal;
082        }
083
084        /**
085         * Returns the server role this protocol implementation is being used for
086         */
087        public ServerRoleEnum getRole() {
088                return myRole;
089        }
090
091        /**
092         * @return The signature profile signer
093         * @see #setSigner(ISigner)
094         */
095        ISigner getSigner() {
096                return mySigner;
097        }
098
099        /**
100         * @return The URI to use for this LLP implementation
101         * @see #setUriPath(String)
102         */
103        public String getUriPath() {
104                return myUriPath;
105        }
106
107        /**
108         * {@inheritDoc}
109         */
110        @Override
111        public HL7Writer getWriter(OutputStream theArg0) throws LLPException {
112                if (myNextReader != null && myNextWriter == null) {
113                        myNextReader = null;
114                        throw new LLPException("Hl7OverHttpLowerLayerProtocol can not be used with a multi socket implementation");
115                }
116                prepareReadersIfNeeded();
117                HohLlpWriter retVal = myNextWriter;
118                retVal.setPreferredCharset(myPreferredCharset);
119                try {
120                        retVal.setOutputStream(theArg0);
121                } catch (IOException e) {
122                        throw new LLPException("Failed to set stream: " + e.getMessage(), e);
123                }
124
125                myNextWriter = null;
126                return retVal;
127        }
128
129        private void prepareReadersIfNeeded() {
130                if (myNextReader == null && myNextWriter == null) {
131                        myNextReader = new HohLlpReader(this);
132                        myNextWriter = new HohLlpWriter(this);
133                        myNextReader.setWriter(myNextWriter);
134                }
135        }
136
137        /**
138         * Provides an authorization callback for authorizing incoming requests. This method
139         * must only be called of this LLP instance is in {@link ServerRoleEnum#SERVER SERVER} mode.
140         */
141        public void setAuthorizationCallback(IAuthorizationClientCallback theAuthorizationClientCallback) {
142                if (myRole == ServerRoleEnum.SERVER) {
143                        throw new IllegalStateException("This LLP implementation is in CLIENT mode, so it can not use an authorization callback");
144                }
145                myAuthorizationClientCallback = theAuthorizationClientCallback;
146        }
147
148        /**
149         * Provides an authorization callback for authorizing incoming requests. This method
150         * must only be called of this LLP instance is in {@link ServerRoleEnum#SERVER SERVER} mode.
151         */
152        public void setAuthorizationCallback(IAuthorizationServerCallback theAuthorizationCallback) {
153                if (myRole == ServerRoleEnum.CLIENT) {
154                        throw new IllegalStateException("This LLP implementation is in CLIENT mode, so it can not use an authorization callback");
155                }
156                myAuthorizationServerCallback = theAuthorizationCallback;
157        }
158
159        /**
160         * @param theSigner The signature profile signer
161         */
162        public void setSigner(ISigner theSigner) {
163                mySigner = theSigner;
164        }
165
166        /**
167         * The URI path to use for this protocol. The URI path is the portion of the address (URL) which
168         * is being accessed which designates the location on the host (i.e. the "path"). By 
169         * default this is set to "/" 
170         * 
171         * @param theUriPath the uri to set
172         */
173        public void setUriPath(String theUriPath) {
174                myUriPath = theUriPath;
175        }
176        
177        /**
178         * Sets the charset which will be used for any initiated outgoing messages. What this
179         * means is that if a message is sent as a response (e.g. an ACK) using this LLP,
180         * the LLP will ignore the charset provided by this method and will attempt to use
181         * the charset used in the original incoming message. On the other hand, if a new
182         * outgoing message is transmitted using this LLP (i.e. not an ACK), the charset
183         * specified here will be used. 
184         */
185        public void setPreferredCharset(Charset thePreferredCharset) {
186                myPreferredCharset = thePreferredCharset;
187        }
188
189}