001: /*
002: * $RCSfile: JAIRMICRIF.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:56:51 $
010: * $State: Exp $
011: */package com.sun.media.jai.rmi;
012:
013: import java.awt.Rectangle;
014: import java.awt.RenderingHints;
015: import java.awt.geom.Rectangle2D;
016: import java.awt.image.RenderedImage;
017: import java.awt.image.renderable.ParameterBlock;
018: import java.awt.image.renderable.RenderContext;
019: import java.awt.image.renderable.RenderableImage;
020: import java.rmi.RemoteException;
021: import java.rmi.Naming;
022: import java.net.InetAddress;
023: import java.util.Iterator;
024: import java.util.Vector;
025: import javax.media.jai.JAI;
026: import javax.media.jai.OperationRegistry;
027: import javax.media.jai.OperationNode;
028: import javax.media.jai.PropertyChangeEventJAI;
029: import javax.media.jai.RenderedOp;
030: import javax.media.jai.remote.RemoteCRIF;
031: import javax.media.jai.remote.JAIRMIDescriptor;
032: import javax.media.jai.remote.NegotiableCapabilitySet;
033: import javax.media.jai.remote.PlanarImageServerProxy;
034: import javax.media.jai.remote.RemoteImagingException;
035: import javax.media.jai.remote.RemoteRenderableOp;
036: import javax.media.jai.remote.RemoteRenderedImage;
037: import javax.media.jai.remote.RemoteRenderedOp;
038: import javax.media.jai.remote.SerializableState;
039: import javax.media.jai.remote.SerializerFactory;
040: import javax.media.jai.remote.SerializableRenderedImage;
041: import javax.media.jai.tilecodec.TileDecoderFactory;
042: import javax.media.jai.util.ImagingListener;
043: import com.sun.media.jai.util.ImageUtil;
044:
045: /**
046: * An implementation of the <code>RemoteRIF</code> interface for the
047: * "jairmi" remote imaging protocol.
048: */
049: public class JAIRMICRIF implements RemoteCRIF {
050:
051: /**
052: * No arg constructor.
053: */
054: public JAIRMICRIF() {
055: }
056:
057: /**
058: * Maps the operation's output <code>RenderContext</code> into a
059: * <code>RenderContext</code> for each of the operation's sources.
060: * This is useful for operations that can be expressed in whole or in
061: * part simply as alterations in the <code>RenderContext</code>, such as
062: * an affine mapping, or operations that wish to obtain lower quality
063: * renderings of their sources in order to save processing effort or
064: * transmission bandwith. Some operations, such as blur, can also
065: * use this mechanism to avoid obtaining sources of higher quality
066: * than necessary.
067: *
068: * @param serverName A <code>String</code> specifying the name of the
069: * server to perform the remote operation on.
070: * @param operationName The <code>String</code> specifying the name of the
071: * operation to be performed remotely.
072: * @param i The index of the source image.
073: * @param renderContext The <code>RenderContext</code> being applied to the
074: * operation.
075: * @param paramBlock A <code>ParameterBlock</code> containing the
076: * operation's sources and parameters.
077: * @param image the <code>RenderableImage</code> being rendered.
078: */
079: public RenderContext mapRenderContext(String serverName,
080: String operationName, int i, RenderContext renderContext,
081: ParameterBlock paramBlock, RenderableImage image)
082: throws RemoteImagingException {
083:
084: // Create the RenderableOp on the server and it's sources on the
085: // appropriate machines.
086: RemoteRenderableOp rrop = (RemoteRenderableOp) image;
087: RenderableRMIServerProxy rmisp = createProxy(rrop);
088:
089: SerializableState rcs = SerializerFactory.getState(
090: renderContext, null);
091:
092: // Perform the mapRenderContext on the server.
093: try {
094: SerializableState rcpOut = rmisp.getImageServer(serverName)
095: .mapRenderContext(i, rmisp.getRMIID(),
096: operationName, rcs);
097: } catch (RemoteException re) {
098: String message = JaiI18N.getString("JAIRMICRIF5");
099: sendExceptionToListener(renderContext, message, re);
100: // throw new RemoteImagingException(ImageUtil.getStackTraceString(re));
101: }
102:
103: return (RenderContext) rcs.getObject();
104: }
105:
106: /**
107: * Returns the bounding box for the output of the operation,
108: * performed on a given set of sources, in rendering-independent
109: * space. The bounds are returned as a <code>Rectangle2D</code>,
110: * that is, an axis-aligned rectangle with floating-point corner
111: * coordinates.
112: *
113: * @param serverName A <code>String</code> specifying the name of the
114: * server to perform the remote operation on.
115: * @param operationName The <code>String</code> specifying the name of the
116: * operation to be performed remotely.
117: * @param paramBlock A <code>ParameterBlock</code> containing the
118: * operation's sources and parameters.
119: * @return a <code>Rectangle2D</code> specifying the rendering-independent
120: * bounding box of the output.
121: */
122: public Rectangle2D getBounds2D(String serverName,
123: String operationName, ParameterBlock paramBlock)
124: throws RemoteImagingException {
125:
126: SerializableState bounds = null;
127:
128: // Create a RemoteRenderableOp that represents the operation.
129: RemoteRenderableOp original = new RemoteRenderableOp("jairmi",
130: serverName, operationName, paramBlock);
131:
132: // Create the RenderableOp on the server alongwith creating the
133: // sources on appropriate machines.
134: RenderableRMIServerProxy rmisp = createProxy(original);
135:
136: try {
137: bounds = rmisp.getImageServer(serverName).getBounds2D(
138: rmisp.getRMIID(), operationName);
139: } catch (RemoteException e) {
140: String message = JaiI18N.getString("JAIRMICRIF6");
141: sendExceptionToListener(null, message, e);
142: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
143: }
144:
145: return (Rectangle2D.Float) bounds.getObject();
146: }
147:
148: /**
149: * Gets the appropriate instance of the property specified by the name
150: * parameter. This method must determine which instance of a property to
151: * return when there are multiple sources that each specify the property.
152: *
153: * @param paramBlock a ParameterBlock containing the operation's
154: * sources and parameters.
155: * @param name a String naming the desired property.
156: * @return an object reference to the value of the property requested.
157: */
158: public Object getProperty(String serverName, String operationName,
159: ParameterBlock paramBlock, String name)
160: throws RemoteImagingException {
161:
162: ParameterBlock pb = null;
163: if (paramBlock == null) {
164: pb = new ParameterBlock();
165: } else {
166: pb = (ParameterBlock) paramBlock.clone();
167: }
168:
169: // Create a RemoteRenderableOp that represents the operation.
170: RemoteRenderableOp original = new RemoteRenderableOp("jairmi",
171: serverName, operationName, paramBlock);
172:
173: // Create the RenderableOp on the server alongwith creating the
174: // sources on appropriate machines.
175: RenderableRMIServerProxy rmisp = createProxy(original);
176:
177: try {
178: return rmisp.getProperty(name);
179: } catch (Exception e) {
180: String message = JaiI18N.getString("JAIRMICRIF7");
181: sendExceptionToListener(null, message,
182: new RemoteImagingException(message, e));
183: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
184: }
185: return null;
186: }
187:
188: /**
189: * Returns a list of names recognized by getProperty.
190: */
191: public String[] getPropertyNames(String serverName,
192: String operationName) throws RemoteImagingException {
193:
194: ImageServer remoteImage = getImageServer(serverName);
195: try {
196: return remoteImage.getPropertyNames(operationName);
197: } catch (RemoteException e) {
198: // Should we be catching Exception or RemoteException
199: String message = JaiI18N.getString("JAIRMICRIF8");
200: sendExceptionToListener(null, message,
201: new RemoteImagingException(message, e));
202: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
203: }
204: return null;
205: }
206:
207: private ImageServer getImageServer(String serverName) {
208:
209: if (serverName == null) {
210: try {
211: serverName = InetAddress.getLocalHost()
212: .getHostAddress();
213: } catch (java.net.UnknownHostException e) {
214: String message = JaiI18N.getString("RMIServerProxy11");
215: sendExceptionToListener(null, message,
216: new RemoteImagingException(message, e));
217: // throw new RuntimeException(e.getMessage());
218: }
219: }
220:
221: // Derive the service name.
222: String serviceName = new String("rmi://" + serverName + "/"
223: + JAIRMIDescriptor.IMAGE_SERVER_BIND_NAME);
224:
225: // Look up the remote object.
226: try {
227: return (ImageServer) Naming.lookup(serviceName);
228: } catch (java.rmi.NotBoundException e) {
229: String message = JaiI18N.getString("RMIServerProxy12");
230: sendExceptionToListener(null, message,
231: new RemoteImagingException(message, e));
232: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
233: } catch (java.net.MalformedURLException e) {
234: String message = JaiI18N.getString("RMIServerProxy12");
235: sendExceptionToListener(null, message,
236: new RemoteImagingException(message, e));
237: } catch (java.rmi.RemoteException e) {
238: String message = JaiI18N.getString("RMIServerProxy12");
239: sendExceptionToListener(null, message,
240: new RemoteImagingException(message, e));
241: }
242:
243: return null;
244: }
245:
246: /**
247: * Returns true if successive renderings (that is, calls to
248: * create(RenderContext, ParameterBlock)) with the same arguments
249: * may produce different results. This method may be used to
250: * determine whether an existing rendering may be cached and
251: * reused. It is always safe to return true.
252: */
253: public boolean isDynamic(String serverName, String operationName)
254: throws RemoteImagingException {
255:
256: ImageServer remoteImage = getImageServer(serverName);
257: try {
258: return remoteImage.isDynamic(operationName);
259: } catch (RemoteException e) {
260: String message = JaiI18N.getString("JAIRMICRIF9");
261: sendExceptionToListener(null, message,
262: new RemoteImagingException(message, e));
263: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
264: }
265: return true;
266: }
267:
268: /**
269: * Creates a <code>RemoteRenderedImage</code> representing the results
270: * of an imaging operation (or chain of operations) for a given
271: * <code>ParameterBlock</code> and <code>RenderingHints</code>. The
272: * <code>RemoteRIF</code> may also query any source images
273: * referenced by the <code>ParameterBlock</code> for their dimensions,
274: * <code>SampleModel</code>s, properties, etc., as necessary.
275: *
276: * <p> The <code>create()</code> method can return null if the
277: * <code>RemoteRIF</code> (representing the server) is not capable of
278: * producing output for the given set of source images and parameters.
279: * For example, if a server (represented by a <code>RemoteRIF</code>) is
280: * only capable of performing a 3x3 convolution on single-banded image
281: * data, and the source image has multiple bands or the convolution
282: * Kernel is 5x5, null should be returned.
283: *
284: * <p> Hints should be taken into account, but can be ignored.
285: * The created <code>RemoteRenderedImage</code> may have a property
286: * identified by the String HINTS_OBSERVED to indicate which
287: * <code>RenderingHints</code> were used to create the image. In addition
288: * any <code>RenderedImage</code>s that are obtained via the getSources()
289: * method on the created <code>RemoteRenderedImage</code> may have such
290: * a property.
291: *
292: * @param serverName A <code>String</code> specifying the name of the
293: * server to perform the remote operation on.
294: * @param operationName The <code>String</code> specifying the name of the
295: * operation to be performed remotely.
296: * @param paramBlock A <code>ParameterBlock</code> containing sources
297: * and parameters for the
298: * <code>RemoteRenderedImage</code> to be created.
299: * @param hints A <code>RenderingHints</code> object containing
300: * hints.
301: * @return A <code>RemoteRenderedImage</code> containing the desired
302: * output.
303: */
304: public RemoteRenderedImage create(String serverName,
305: String operationName, ParameterBlock paramBlock,
306: RenderingHints hints) throws RemoteImagingException {
307:
308: // Create the RenderedOp on the server
309: RMIServerProxy rmisp = new RMIServerProxy(serverName,
310: operationName, paramBlock, hints);
311:
312: // Check whether there is a RIF on the server that can satisfy this
313: // rendering request.
314: boolean cbr = rmisp.canBeRendered();
315:
316: if (!cbr) {
317: return null;
318: } else {
319: return rmisp;
320: }
321: }
322:
323: /**
324: * Creates a <code>RemoteRenderedImage</code> representing the results
325: * of an imaging operation, whose given old rendering is updated
326: * according to the given <code>PropertyChangeEventJAI</code>. This
327: * factory method should be used to create a new rendering updated
328: * according to the changes reported by the given
329: * <code>PropertyChangeEventJAI</code>. The <code>RemoteRIF</code>
330: * can query the supplied <code>PlanarImageServerProxy</code> for
331: * references to the server name, operation name, parameter block,
332: * and rendering hints. The <code>RemoteRIF</code> may also query
333: * any source images referenced by the <code>ParameterBlock</code>
334: * for their dimensions, <code>SampleModel</code>s, properties, etc.,
335: * as necessary.
336: *
337: * <p> The <code>create()</code> method can return null if the
338: * <code>RemoteRIF</code> (representing the server) is not capable of
339: * producing output for the given set of source images and parameters.
340: * For example, if a server (represented by a <code>RemoteRIF</code>) is
341: * only capable of performing a 3x3 convolution on single-banded image
342: * data, and the source image has multiple bands or the convolution
343: * Kernel is 5x5, null should be returned.
344: *
345: * <p> Hints should be taken into account, but can be ignored.
346: * The created <code>RemoteRenderedImage</code> may have a property
347: * identified by the String HINTS_OBSERVED to indicate which
348: * <code>RenderingHints</code> were used to create the image. In addition
349: * any <code>RenderedImage</code>s that are obtained via the getSources()
350: * method on the created <code>RemoteRenderedImage</code> may have such
351: * a property.
352: *
353: * @param oldRendering The old rendering of the imaging operation.
354: * @param event An event that specifies the changes made to the
355: * imaging operation.
356: * @return A <code>RemoteRenderedImage</code> containing the desired
357: * output.
358: */
359: public RemoteRenderedImage create(
360: PlanarImageServerProxy oldRendering, OperationNode node,
361: PropertyChangeEventJAI event) throws RemoteImagingException {
362:
363: if (!(node instanceof RemoteRenderedOp))
364: return null;
365:
366: String propName = event.getPropertyName();
367: RMIServerProxy rmisp;
368: if (propName.equals("servername")) {
369: rmisp = new RMIServerProxy(oldRendering, node,
370: (String) event.getNewValue());
371: } else if (propName.equals("operationregistry")
372: || propName.equals("protocolname")
373: || propName.equals("protocolandservername")) {
374:
375: return create(((RemoteRenderedOp) node).getServerName(),
376: node.getOperationName(), node.getParameterBlock(),
377: node.getRenderingHints());
378:
379: } else {
380: rmisp = new RMIServerProxy(oldRendering, node, event);
381: }
382:
383: return rmisp;
384: }
385:
386: /**
387: * Creates a rendering, given a <code>RenderContext</code> and a
388: * <code>ParameterBlock</code> containing the operation's sources
389: * and parameters. The output is a <code>RemoteRenderedImage</code>
390: * that takes the <code>RenderContext</code> into account to
391: * determine its dimensions and placement on the image plane.
392: * This method houses the "intelligence" that allows a
393: * rendering-independent operation to adapt to a specific
394: * <code>RenderContext</code>.
395: *
396: * @param serverName A <code>String</code> specifying the name of the
397: * server to perform the remote operation on.
398: * @param operationName The <code>String</code> specifying the name of the
399: * operation to be performed remotely.
400: * @param renderContext The <code>RenderContext</code> specifying the
401: * rendering context.
402: * @param paramBlock A <code>ParameterBlock</code> containing the
403: * operation's sources and parameters.
404: */
405: public RemoteRenderedImage create(String serverName,
406: String operationName, RenderContext renderContext,
407: ParameterBlock paramBlock) throws RemoteImagingException {
408:
409: // Create the RenderableOp on the server.
410: RMIServerProxy rmisp = new RMIServerProxy(serverName,
411: operationName, paramBlock, renderContext, true);
412:
413: // Cause a rendering to take place, so we can return a RenderedImage
414: // since we can't return a RenderableOp.
415: Long renderingID = rmisp.getRenderingID();
416:
417: // Return an RMIServerProxy that is a link to the rendering on the
418: // server.
419: return new RMIServerProxy((serverName + "::" + renderingID),
420: paramBlock, operationName, renderContext
421: .getRenderingHints());
422: }
423:
424: /**
425: * Returns the set of capabilities supported by the client object.
426: */
427: public NegotiableCapabilitySet getClientCapabilities() {
428:
429: OperationRegistry registry = JAI.getDefaultInstance()
430: .getOperationRegistry();
431: String modeName = "tileDecoder";
432: String[] descriptorNames = registry
433: .getDescriptorNames(modeName);
434: TileDecoderFactory tdf = null;
435:
436: // Only non-preference NegotiableCapability objects can be added
437: // to this NCS, which is ok, since these represent the capabilities
438: // of the client and thus are not preferences as much as they are
439: // hard capabilities (i.e. non-preferences)
440: NegotiableCapabilitySet capabilities = new NegotiableCapabilitySet(
441: false);
442:
443: // Note that tileEncoder capabilities cannot be added since there is
444: // no way to differentiate between a encoding and a decoding capability
445: // within an NCS, and since the client should only be expected to
446: // decode, this should be ok.
447:
448: Iterator it;
449: for (int i = 0; i < descriptorNames.length; i++) {
450:
451: it = registry.getFactoryIterator(modeName,
452: descriptorNames[i]);
453: for (; it.hasNext();) {
454: tdf = (TileDecoderFactory) it.next();
455: capabilities.add(tdf.getDecodeCapability());
456: }
457: }
458:
459: return capabilities;
460: }
461:
462: // Recursive evaluation of sources.
463:
464: /**
465: * Create a <code>RenderableRMIServerProxy</code> that represents
466: * a remote Renderable operation. This method examines the operation's
467: * sources recursively and creates them as needed.
468: */
469: private RenderableRMIServerProxy createProxy(RemoteRenderableOp rop) {
470:
471: ParameterBlock oldPB = rop.getParameterBlock();
472: ParameterBlock newPB = (ParameterBlock) oldPB.clone();
473: Vector sources = oldPB.getSources();
474: newPB.removeSources();
475:
476: // Create a new RenderableOp on the server
477: ImageServer remoteImage = getImageServer(rop.getServerName());
478: ImagingListener listener = ImageUtil.getImagingListener(rop
479: .getRenderingHints());
480: Long opID = new Long(0L);
481: try {
482: opID = remoteImage.getRemoteID();
483: remoteImage.createRenderableOp(opID,
484: rop.getOperationName(), newPB);
485: } catch (RemoteException e) {
486: String message = JaiI18N.getString("RMIServerProxy8");
487: listener.errorOccurred(message, new RemoteImagingException(
488: message, e), this , false);
489: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
490: }
491:
492: // Now look at the sources of the RenderableOp
493: if (sources != null) {
494:
495: for (int i = 0; i < sources.size(); i++) {
496:
497: Object source = sources.elementAt(i);
498:
499: if (source instanceof RemoteRenderedOp) {
500:
501: // If source is a RenderedOp on a remote machine, create
502: // it on the remote machine.
503: RMIServerProxy rmisp = (RMIServerProxy) (((RemoteRenderedOp) source)
504: .getRendering());
505:
506: try {
507: if (rmisp.getServerName().equalsIgnoreCase(
508: rop.getServerName())) {
509:
510: // Both the RenderableOp and this source are on
511: // the same server.
512: remoteImage.setRenderedSource(opID, rmisp
513: .getRMIID(), i);
514: newPB.setSource(rmisp, i);
515: } else {
516:
517: // The RenderableOp and this source are on
518: // different servers.
519: remoteImage.setRenderedSource(opID, rmisp
520: .getRMIID(), rmisp.getServerName(),
521: rmisp.getOperationName(), i);
522: newPB.setSource(rmisp, i);
523: }
524: } catch (RemoteException e) {
525: String message = JaiI18N
526: .getString("RMIServerProxy6");
527: listener.errorOccurred(message,
528: new RemoteImagingException(message, e),
529: this , false);
530: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
531: }
532:
533: } else if (source instanceof RenderedOp) {
534:
535: // If the source is a local RenderedOp, then the only way
536: // to access it from a remote machine is to render it and
537: // create a SerializableRenderedImage wrapping the
538: // rendering, which is set as the source of the remote op.
539: RenderedImage ri = ((RenderedOp) source)
540: .getRendering();
541: try {
542: SerializableRenderedImage sri = new SerializableRenderedImage(
543: ri);
544: remoteImage.setRenderedSource(opID, sri, i);
545: newPB.setSource(sri, i);
546: } catch (RemoteException e) {
547: String message = JaiI18N
548: .getString("RMIServerProxy6");
549: listener.errorOccurred(message,
550: new RemoteImagingException(message, e),
551: this , false);
552: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
553: }
554:
555: } else if (source instanceof RenderedImage) {
556:
557: // If the source is a local RenderedImage, then the only
558: // way to access it from a remote machine is by wrapping
559: // it in SerializableRenderedImage and then setting the
560: // SRI as the source.
561: RenderedImage ri = (RenderedImage) source;
562: try {
563: SerializableRenderedImage sri = new SerializableRenderedImage(
564: ri);
565: remoteImage.setRenderedSource(opID, sri, i);
566: newPB.setSource(sri, i);
567: } catch (RemoteException e) {
568: String message = JaiI18N
569: .getString("RMIServerProxy6");
570: listener.errorOccurred(message,
571: new RemoteImagingException(message, e),
572: this , false);
573: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
574: }
575:
576: } else if (source instanceof RemoteRenderableOp) {
577:
578: // If the source is a RenderableOp on a remote machine,
579: // cause the RenderableOp to be created on the remote
580: // machine.
581: RenderableRMIServerProxy rrmisp = createProxy((RemoteRenderableOp) source);
582:
583: try {
584:
585: // If the source RenderableOp is on the same server
586: // as the RenderableOp that represents the operation
587: if (rrmisp.getServerName().equalsIgnoreCase(
588: rop.getServerName())) {
589: remoteImage.setRenderableSource(opID,
590: rrmisp.getRMIID(), i);
591: newPB.setSource(rrmisp, i);
592: } else {
593: // If the source RenderableOp is on a different
594: // server than the RenderableOp that represents
595: // the operation
596: remoteImage
597: .setRenderableRMIServerProxyAsSource(
598: opID, rrmisp.getRMIID(),
599: rrmisp.getServerName(),
600: rrmisp.getOperationName(),
601: i);
602: newPB.setSource(rrmisp, i);
603: }
604: } catch (RemoteException e) {
605: String message = JaiI18N
606: .getString("RMIServerProxy6");
607: listener.errorOccurred(message,
608: new RemoteImagingException(message, e),
609: this , false);
610: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
611: }
612:
613: } else if (source instanceof RenderableImage) {
614:
615: // If the source is a local RenderableImage, the only way
616: // to access it from a remote machine is to wrap it in
617: // a SerializableRenderableImage and then set the SRI as
618: // the source on the remote operation.
619: RenderableImage ri = (RenderableImage) source;
620: try {
621: SerializableRenderableImage sri = new SerializableRenderableImage(
622: ri);
623: remoteImage.setRenderableSource(opID, sri, i);
624: newPB.setSource(sri, i);
625: } catch (RemoteException e) {
626: String message = JaiI18N
627: .getString("RMIServerProxy6");
628: listener.errorOccurred(message,
629: new RemoteImagingException(message, e),
630: this , false);
631: // throw new RemoteImagingException(ImageUtil.getStackTraceString(e));
632: }
633: }
634:
635: }
636: }
637:
638: // Create a new RMIServerProxy to access the RenderableOp
639: // created at the beginning of this method.
640: RenderableRMIServerProxy finalRmisp = new RenderableRMIServerProxy(
641: rop.getServerName(), rop.getOperationName(), newPB,
642: opID);
643: return finalRmisp;
644: }
645:
646: private void sendExceptionToListener(RenderContext renderContext,
647: String message, Exception e) {
648: ImagingListener listener = ImageUtil
649: .getImagingListener(renderContext);
650: listener.errorOccurred(message, new RemoteImagingException(
651: message, e), this , false);
652: }
653: }
|