ForwardingControlImpl.mesa
Copyright (C) Xerox Corporation 1984, 1985. All rights reserved.
Last edited by Jacks 6-Nov-85 14:03:03
Tim Diebert: December 29, 1986 11:17:25 am PST
<<This module controls the forwarding of documents (IP masters) to other Print Services. It has been implemented as part of the FEPS.>>
DIRECTORY
ControlMessages USING [Key],
ForwardingControl USING [CancelProc, TraceLevel, WaitChoice],
MiscUtilities USING [KeyForCommunicationStatus],
NSFile USING [Attribute, Close, Error, Handle, Open, nullHandle, nullTime, Session, Time],
NSString USING [String, StringFromMesaString],
PaperTypes USING [Paper],
PrintingTypes USING [Option],
PrintQueue USING [Empty, nilQueueObjectHandle, Priority, ObjectStatus, QueueObjectHandle, QueueStage, QueueWatcher, Requeue],
Process USING [Detach, Pause, Priority, SecondsToTicks, SetPriority, SetTimeout],
PSAssignedTypes USING [tSpooled],
PSAsyncMsg USING [ExpandArrayAndPutString, Insert, Proc, PutMesaString],
PSKMessages USING [GetHandle],
PSVolume USING [GetDefaultSession, GetDirectory],
String USING [AppendDecimal, AppendLongDecimal, Overflow, StringBoundsFault],
System USING [gmtEpoch, GetGreenwichMeanTime, NetworkAddress, nullNetworkAddress, nullID, Overflow, SecondsSinceEpoch, UniversalID],
TargetPS USING [Error, ForwardDocument],
TargetPSStatus USING [Communication],
XMessage USING [Handle, MsgKey];
ForwardingControlImpl: CEDAR MONITOR
IMPORTS MiscUtilities, NSFile, NSString, PrintQueue, Process, PSAsyncMsg, PSKMessages, PSVolume, String, System, TargetPS
EXPORTS ForwardingControl =
BEGIN
Control: TYPE = RECORD [
stop: BOOLEANTRUE,
start: BOOLEANFALSE,
jobQueueEntry: BOOLEANFALSE,
tpQueueEntry: BOOLEANFALSE
];
State: TYPE = RECORD [
stopped: BOOLEANTRUE,
forwarding: BOOLEANFALSE,
lastForwardingStatus: TargetPSStatus.Communication ← okay,
targetPS: XNS.Address ← XNS.nullAddress,
tpJob: BOOLEANFALSE,
file: FS.OpenFile ← FS.nullOpenFile,
trace: ForwardingControl.TraceLevel ← none,
qOH: PrintQueue.QueueObjectHandle ← PrintQueue.nilQueueObjectHandle,
stopStatus: PrintQueue.ObjectStatus ← canceledInForwarder, --specified in Stop call
canceledWhileForwarding: ForwardingControl.CancelProc ← NIL,
putAsyncMsgFromKey: PSAsyncMsg.Proc ← NIL,
startForwardingTime: BasicTime.GMT ← BasicTime.nullGMT
];
event: CONDITION;
stopped: CONDITION;
control: Control ← [];
state: State ← [];
Message domain handle:
controlMsgs: XMessage.Handle ← PSKMessages.GetHandle[control];
session: NSFile.Session = PSVolume.GetDefaultSession[];
Init: PUBLIC ENTRY PROCEDURE [currentOption: PrintingTypes.Option, priority: Process.Priority,
putAsyncMsgFromKey: PSAsyncMsg.Proc] = TRUSTED BEGIN
ENABLE UNWIND => NULL;
IF currentOption # feps9700 THEN ERROR;
state ← [putAsyncMsgFromKey: putAsyncMsgFromKey];
PrintQueue.QueueWatcher[proc: JobQueueEntry, queueStage: merged];
PrintQueue.QueueWatcher[proc: TPQueueEntry, queueStage: tpMerged];
Process.SetTimeout[@event, Process.SecondsToTicks[seconds: 30]]; --check queue every 30 secs
Process.Detach[FORK ForwardingControlLoop[priority]];
END; --Init
Start: PUBLIC ENTRY PROCEDURE = BEGIN
ENABLE UNWIND => NULL;
control.start ← TRUE;
control.stop ← FALSE;
NOTIFY event;
END; --Start
Stop: PUBLIC ENTRY PROCEDURE [status: PrintQueue.ObjectStatus,
canceledWhileForwarding: ForwardingControl.CancelProc ← NIL] = BEGIN
ENABLE UNWIND => NULL;
state.stopStatus ← status;
state.canceledWhileForwarding ← canceledWhileForwarding;
control.stop ← TRUE;
control.start ← FALSE;
NOTIFY event;
END; --Stop
Stopped: PUBLIC ENTRY PROCEDURE [wither: ForwardingControl.WaitChoice ← dontWait]
RETURNS
[BOOLEAN] = BEGIN
ENABLE UNWIND => NULL;
IF wither = wait THEN UNTIL state.stopped DO
WAIT stopped;
ENDLOOP;
RETURN [state.stopped];
END; --Stopped
Status: PUBLIC PROCEDURE RETURNS [
forwarding: BOOLEAN, --returns TRUE if forwarding in progress
forwardingStatus: TargetPSStatus.Communication --valid if forwarding = TRUE--] = BEGIN
ENABLE UNWIND => NULL;
forwarding ← state.forwarding;
forwardingStatus ← state.lastForwardingStatus;
END; --Status
SetTargetPrintService: PUBLIC ENTRY PROCEDURE [address: XNS.Address] = BEGIN
ENABLE UNWIND => NULL;
state.targetPS ← address;
END; --SetTargetPrintService
ModifyTraceLevel: PUBLIC ENTRY PROCEDURE [trace: ForwardingControl.TraceLevel] = BEGIN
ENABLE UNWIND => NULL;
state.trace ← trace;
END; --ModifyTraceLevel
JobQueueEntry: ENTRY PROCEDURE = BEGIN -- called by PrintQueue
ENABLE UNWIND => NULL;
control.jobQueueEntry ← TRUE;
NOTIFY event;
IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["//Forwarding JobQEntry"];
END; --JobQueueEntry
TPQueueEntry: ENTRY PROCEDURE = BEGIN --called by PrintQueue when TestPattern is queued
ENABLE UNWIND => NULL;
control.tpQueueEntry ← TRUE;
NOTIFY event;
IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["//Forwarding TPQEntry"];
END; --TPQueueEntry
ForwardingControlLoop: ENTRY PROCEDURE [priority: Process.Priority] = BEGIN
ENABLE UNWIND => NULL;
Process.SetPriority[priority];
DO --forever
SELECT TRUE FROM
control.tpQueueEntry AND NOT state.forwarding => BEGIN --over-rides state.stopped
state.qOH ← PrintQueue.Requeue[fromQueue: tpMerged, toQueue: forwarding];
IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN
control.tpQueueEntry ← FALSE;
LOOP;
END;
state.tpJob ← TRUE;
ForwardDocument[];
END;
control.stop => BEGIN --disables forwarding; forwarding in progress is aborted
If we're currently forwarding, wait for forwarding proc to notice
control.stop and quit forwarding. Then event will be notified again in Queue
and we'll come around to the ENDCASE and set stopped to TRUE.
SELECT TRUE FROM
state.forwarding => NULL;
ENDCASE => BEGIN
control.stop ← FALSE;
state.stopped ← TRUE;
NOTIFY stopped;
END;
END;
control.start => BEGIN
state.stopped ← control.start ← FALSE; -- so we don't keep looking here
LOOP; -- make another pass
END;
state.stopped => NULL;
state.forwarding => NULL; --so we don't start multiple forwarding operations
control.jobQueueEntry => BEGIN
state.qOH ← PrintQueue.Requeue[fromQueue: merged, toQueue: forwarding];
IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN
control.jobQueueEntry ← FALSE;
LOOP;
END;
ForwardDocument[];
END;
ENDCASE;
WAIT event;
ENDLOOP;
END; --ForwardingControlLoop
ForwardDocument: INTERNAL PROCEDURE = BEGIN
state.lastForwardingStatus ← okay; --reset before trying to forward new document
state.forwarding ← TRUE;
state.qOH.currentStatus ← forwarding;
Process.Detach[FORK DoForwarding[]];
END; --ForwardDocument
DoForwarding: PROCEDURE = BEGIN
stringArray: ARRAY [0..2) OF NSString.String;
sForwarding: LONG STRING = "//Forwarding ""<1>""; Attempt number: <2>"L;
nsForwarding: NSString.String = Str[sForwarding];
sAttempts: LONG STRING ← [10];
forwardingAttempts: CARDINAL ← 0;
requestID: System.UniversalID ← System.nullID;
WITH q: state.qOH SELECT FROM
feps9700 => BEGIN
First open the interleaved interpress master (merged) file:
attributesList: ARRAY [0..1) OF NSFile.Attribute;
spoolDirectory: NSFile.Handle ← PSVolume.GetDirectory[PSAssignedTypes.tSpooled];
attributesList[0] ← [fileID[q.ivFileID]]; --ID of merged file
state.file ← NSFile.Open[
attributes: DESCRIPTOR[attributesList],
directory: spoolDirectory, session: session
! NSFile.Error => {
PSAsyncMsg.PutMesaString["//CAN'T OPEN MERGED FILE!"L];
GOTO Abort}];
state.startForwardingTime ← BasicTime.Now[];
DO --Keep trying to forward the document until success or cancellation:
BEGIN
forwardingAttempts ← forwardingAttempts + 1;
IF state.trace # none THEN BEGIN
stringArray[0] ← state.qOH.fileName;
sAttempts.length ← 0;
String.AppendDecimal[s: sAttempts, n: forwardingAttempts];
stringArray[1] ← Str[sAttempts];
PSAsyncMsg.ExpandArrayAndPutString[nsForwarding, DESCRIPTOR[stringArray]];
END;
q.targetRequestID ← TargetPS.ForwardDocument[
target: state.targetPS,
master: state.file,
docName: state.qOH.fileName,
sender: state.qOH.sender,
recipient: state.qOH.recipient,
message: state.qOH.operatorMsg,
copies: IF state.qOH.bannerOnly THEN 1 ELSE state.qOH.numberCopies,
paper: state.qOH.paper,
docCreateDate: state.qOH.fileCreateDate,
priority: state.qOH.priority,
staple: state.qOH.staple,
twoSided: state.qOH.twoSided
! TargetPS.Error => {
IF state.lastForwardingStatus # why THEN DisplayForwardingStatus[why];
state.lastForwardingStatus ← why;
q.forwardingStatus ← why; --update print queue
GOTO TryAgain}];
EXITS
TryAgain => BEGIN
IF control.stop = TRUE THEN GOTO Stop;
Pause before retrying, unless Target PS is not responding, in which case we've already waited a long time...
IF state.lastForwardingStatus # remoteSystemElementNotResponding THEN
Process.Pause[Process.SecondsToTicks[30]];
LOOP;
END;
END;
EXIT; --Will always exit loop unless a signal is caught.
ENDLOOP;
IF state.lastForwardingStatus # okay THEN DisplayForwardingStatus[okay];
state.lastForwardingStatus ← okay;
Queue[status: forwarded];
END; --of state.qOH select stmt
ENDCASE => ERROR; --engine # feps9700
EXITS
Abort => Queue[status: forwardFailure];
Stop => Queue[status: state.stopStatus];
END; --DoForwarding
Queue: ENTRY PROCEDURE [status: PrintQueue.ObjectStatus] = BEGIN
ENABLE UNWIND => NULL;
IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN
IF state.trace # none THEN PSAsyncMsg.PutMesaString["##Can't Queue nilQOH! "];
RETURN;
END;
IF state.trace # none THEN BEGIN
forwardTime: LONG CARDINAL ← 0;
sDoneForwarding: LONG STRING ← "//Done Forwarding ""<1>""; status= <2>; seconds= <3>"L;
sSeconds: LONG STRING ← [10];
nsDoneForwarding: NSString.String ← Str[sDoneForwarding];
stringArray: ARRAY [0..3) OF NSString.String;
startSinceEpoch: LONG CARDINAL ← System.SecondsSinceEpoch[state.startForwardingTime];
endSinceEpoch: LONG CARDINAL ← System.SecondsSinceEpoch[System.GetGreenwichMeanTime[]];
IF endSinceEpoch >= startSinceEpoch THEN
forwardTime ← endSinceEpoch - startSinceEpoch;
stringArray[0] ← state.qOH.fileName;
stringArray[1] ← Str[SELECT status FROM
merged => "merged"L,
canceledInForwarder => "canceledInForwarder"L,
forwardFailure => "forwardFailure"L,
ENDCASE => "forwarded"L];
String.AppendLongDecimal[sSeconds, forwardTime
! System.Overflow, String.Overflow, String.StringBoundsFault => CONTINUE];
stringArray[2] ← Str[sSeconds];
PSAsyncMsg.ExpandArrayAndPutString[nsDoneForwarding, DESCRIPTOR[stringArray]]
END;
state.qOH.currentStatus ← status;
IF state.file # NSFile.nullHandle THEN
NSFile.Close[state.file, session]; --close interleaved ip file
SELECT TRUE FROM
status = merged => BEGIN
[] ← PrintQueue.Requeue[
qOH: state.qOH, fromQueue: forwarding, toQueue: merged, position: front];
END;
status = canceledInForwarder => BEGIN
[] ← PrintQueue.Requeue[
qOH: state.qOH, fromQueue: forwarding, toQueue: aborted];
IF state.canceledWhileForwarding # NIL THEN
state.canceledWhileForwarding[state.qOH.fileName, status];
END;
status # forwarded =>
[] ← PrintQueue.Requeue[
qOH: state.qOH, fromQueue: forwarding, toQueue: aborted];
ENDCASE =>
[] ← PrintQueue.Requeue[
qOH: state.qOH, fromQueue: forwarding, toQueue: forwarded];
state.file ← NSFile.nullHandle;
state.forwarding ← state.tpJob ← FALSE;
state.qOH ← PrintQueue.nilQueueObjectHandle;
control.jobQueueEntry ← NOT PrintQueue.Empty[merged];
control.tpQueueEntry ← NOT PrintQueue.Empty[tpMerged];
NOTIFY event; -- in case there's something to do
END; --Queue
DisplayForwardingStatus: PROCEDURE [why: TargetPSStatus.Communication] = BEGIN
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert ← ALL[];
insertArray[0].m ← MiscUtilities.KeyForCommunicationStatus[why];
state.putAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mForwardingError]],
insertArray: DESCRIPTOR[insertArray]];
END; --DisplayForwardingStatus
XKey: PROCEDURE [key: ControlMessages.Key] RETURNS [xKey: XMessage.MsgKey] =
{RETURN[ORD[key]]};
Str: PROCEDURE [s: REF TEXT] RETURNS [ns: NSString.String] = INLINE {
RETURN[NSString.StringFromMesaString[s]]};
END. -- of ForwardingControlImpl
LOG when/who/what
22-Oct-84 10:44:03 - Jacks - Created.
29-Oct-84 11:53:06 - Jacks - Added bannerOnly reference in call to ForwardDocument; added call to TargetPS.ForwardDocument.
16-Nov-84 12:05:05 - Jacks - Updated to second round of 9.0 ps interface changes.
29-Nov-84 15:55:11 - Jacks - Store forwarding status in queue; status=merged NOT restart for retrying.
17-Jan-85 14:46:42 - Jacks - Added reset of lastForwardingStatus in ForwardDocument proc; added prefix "ps" to msg keys for 9.0.
23-Jan-85 15:29:23 - Jacks - Changed retry pause when forwarding error back to 30 sec.
8-Mar-85 15:21:03 - Jacks - Changes to handling forwarding errors: only display one msg for each type of error encountered, display "okay" when successful, don't wait before retrying on remoteSystemElementNotResponding.
17-Jun-85 16:16:35 - Jacks - Added copyright notice; updated to PS Euclid interfaces.
19-Jul-85 18:00:52 - Jacks - Updated to XMessage.
6-Nov-85 14:03:00 - Jacks - Get msg handle from PSKMessages.