/// <summary> Validates the given message against our accept validators, attempts to commit /// the message to safe storage, and returns an ACK message indicating acceptance /// or rejection at the accept level (see enhanced mode processing rules in HL7 /// chapter 2, v2.5). /// </summary> public static AcceptACK validate(NuGenProcessorContext theContext, NuGenTransportable theMessage) { AcceptACK ruling = null; NuGenAcceptValidator[] validators = theContext.Validators; for (int i = 0; i < validators.Length && ruling == null; i++) { Genetibase.NuGenHL7.protocol.AcceptRuling vr = validators[i].check(theMessage); if (!vr.Acceptable) { System.String description = (vr.Reasons.Length > 0)?vr.Reasons[0]:null; NuGenTransportable ack = makeAcceptAck(theMessage, vr.AckCode, vr.ErrorCode, description); ruling = new AcceptACK(false, ack); } } if (ruling == null) { try { theContext.SafeStorage.store(theMessage); NuGenTransportable ack = makeAcceptAck(theMessage, Genetibase.NuGenHL7.protocol.Processor_Fields.CA, NuGenHL7Exception.MESSAGE_ACCEPTED, ""); ruling = new AcceptACK(true, ack); } catch (NuGenHL7Exception e) { int code = NuGenHL7Exception.APPLICATION_INTERNAL_ERROR; NuGenTransportable ack = makeAcceptAck(theMessage, Genetibase.NuGenHL7.protocol.Processor_Fields.CR, code, e.Message); ruling = new AcceptACK(false, ack); } } return ruling; }
/// <summary> Validates the given message against our accept validators, attempts to commit /// the message to safe storage, and returns an ACK message indicating acceptance /// or rejection at the accept level (see enhanced mode processing rules in HL7 /// chapter 2, v2.5). /// </summary> public static AcceptACK validate(NuGenProcessorContext theContext, NuGenTransportable theMessage) { AcceptACK ruling = null; NuGenAcceptValidator[] validators = theContext.Validators; for (int i = 0; i < validators.Length && ruling == null; i++) { Genetibase.NuGenHL7.protocol.AcceptRuling vr = validators[i].check(theMessage); if (!vr.Acceptable) { System.String description = (vr.Reasons.Length > 0)?vr.Reasons[0]:null; NuGenTransportable ack = makeAcceptAck(theMessage, vr.AckCode, vr.ErrorCode, description); ruling = new AcceptACK(false, ack); } } if (ruling == null) { try { theContext.SafeStorage.store(theMessage); NuGenTransportable ack = makeAcceptAck(theMessage, Genetibase.NuGenHL7.protocol.Processor_Fields.CA, NuGenHL7Exception.MESSAGE_ACCEPTED, ""); ruling = new AcceptACK(true, ack); } catch (NuGenHL7Exception e) { int code = NuGenHL7Exception.APPLICATION_INTERNAL_ERROR; NuGenTransportable ack = makeAcceptAck(theMessage, Genetibase.NuGenHL7.protocol.Processor_Fields.CR, code, e.Message); ruling = new AcceptACK(false, ack); } } return(ruling); }
/// <param name="theContext">source of supporting services /// </param> /// <param name="isThreaded">true if this class should create threads in which to call cycle(), and /// in which to send responses from Applications. This is the preferred mode. Use false /// if threading is not allowed, eg you are running the code in an EJB container. In this case, /// the send() and receive() methods will call cycle() themselves as needed. However, cycle() /// makes potentially blocking calls, so these methods may not return until the next message /// is received from the remote server, regardless of timeout. Probably the worst example of this /// would be if receive() was called to wait for an application ACK that was specified as "RE" (ie /// required on error). No response will be returned if the message is processed without error, /// and in a non-threaded environment, receive() will block forever. Use true if you can, otherwise /// study this class carefully. /// /// TODO: write a MLLPTransport with non-blocking IO /// TODO: reconnect transport layers on error and retry /// </param> public NuGenProcessorImpl(NuGenProcessorContext theContext, bool isThreaded) { myContext = theContext; myThreaded = isThreaded; myAcceptAcks = new System.Collections.Hashtable(); myReservations = new System.Collections.Hashtable(); myAvailableMessages = new System.Collections.Hashtable(); if (isThreaded) { ackCycler = new Cycler(this, true); SupportClass.ThreadClass ackThd = new SupportClass.ThreadClass(new System.Threading.ThreadStart(ackCycler.Run)); ackThd.Start(); nonAckCycler = new Cycler(this, false); SupportClass.ThreadClass nonAckThd = new SupportClass.ThreadClass(new System.Threading.ThreadStart(nonAckCycler.Run)); nonAckThd.Start(); } }
/// <summary> Accepts a single inbound connection if the same ServerSocket is used for /// all message exchanges, or a connection from each if two ServerSockets are /// being used. /// /// </summary> /// <param name="theAddress">the IP address from which to accept connections (null means /// accept from any address). Connection attempts from other addresses will /// be ignored. /// </param> /// <returns> a <code>Processor</code> connected to the given address /// </returns> /// <throws> TransportException </throws> public virtual NuGenProcessor accept(System.String theAddress) { NuGenTransportLayer transport = getTransport(myServerSocket, theAddress); NuGenProcessorContext context = null; if (myServerSocket2 == null) { //we're doing inbound & outbound on the same port transport.connect(); context = new NuGenProcessorContextImpl(myRouter, transport, myStorage); } else { NuGenTransportLayer transport2 = getTransport(myServerSocket2, theAddress); NuGenDualTransportConnector connector = new NuGenDualTransportConnector(transport, transport2); connector.connect(); context = new NuGenProcessorContextImpl(myRouter, transport, transport2, myStorage); } return(new NuGenProcessorImpl(context, true)); }