0001: /*
0002: * $RCSfile: RemoteJAI.java,v $
0003: *
0004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Use is subject to license terms.
0007: *
0008: * $Revision: 1.2 $
0009: * $Date: 2005/05/12 18:24:34 $
0010: * $State: Exp $
0011: */package javax.media.jai.remote;
0012:
0013: import java.awt.RenderingHints;
0014: import java.awt.image.RenderedImage;
0015: import java.awt.image.renderable.ParameterBlock;
0016: import java.awt.image.renderable.RenderableImage;
0017: import java.text.MessageFormat;
0018: import java.util.ArrayList;
0019: import java.util.Hashtable;
0020: import java.util.Iterator;
0021: import java.util.List;
0022: import java.util.Locale;
0023: import java.util.Map;
0024: import java.util.Vector;
0025: import javax.media.jai.JAI;
0026: import javax.media.jai.OperationRegistry;
0027: import javax.media.jai.OperationDescriptor;
0028: import javax.media.jai.PlanarImage;
0029: import javax.media.jai.RenderedOp;
0030: import javax.media.jai.RenderableOp;
0031: import javax.media.jai.TileCache;
0032: import javax.media.jai.util.CaselessStringKey;
0033: import javax.media.jai.util.ImagingException;
0034: import javax.media.jai.util.ImagingListener;
0035: import com.sun.media.jai.util.ImageUtil;
0036:
0037: /**
0038: * A convenience class for instantiating operations on remote machines.
0039: *
0040: * This class also provides information related to the server and allows
0041: * for setting of parameters for the remote communication with the server.
0042: *
0043: * <p>Conceptually this class is very similar to the <code>JAI</code>
0044: * class, except that the <code>RemoteJAI</code> class deals with
0045: * remote operations. This class allows programmers to use the syntax:
0046: *
0047: * <pre>
0048: * import javax.media.jai.remote.RemoteJAI;
0049: * RemoteJAI rc = new RemoteJAI(protocolName, serverName);
0050: * RemoteRenderedOp im = rc.create("convolve", paramBlock, renderHints);
0051: * </pre>
0052: *
0053: * to create new images by applying operators that are executed remotely on
0054: * the specified server. The <code>create()</code> method returns a
0055: * <code>RemoteRenderedOp</code> encapsulating the protocol name, server
0056: * name, operation name, parameter block, and rendering hints. Additionally,
0057: * it performs validity checking on the operation parameters. The operation
0058: * parameters are determined from the <code>OperationDescriptor</code>
0059: * retrieved using the <code>getServerSupportedOperationList()</code> method.
0060: * Programmers may also refer to
0061: * RemoteJAI.createRenderable("opname", paramBlock, renderHints);
0062: *
0063: * <p> If the <code>OperationDescriptor</code> associated with the
0064: * named operation returns <code>true</code> from its
0065: * <code>isImmediate()</code> method, the <code>create()</code>
0066: * method will ask the <code>RemoteRenderedOp</code> it constructs to render
0067: * itself immediately. If this rendering is <code>null</code>,
0068: * <code>create()</code> will itself return <code>null</code>
0069: * rather than returning an instance of <code>RemoteRenderedOp</code>
0070: * as it normally does.
0071: *
0072: * <p> The registry being used by this class may be
0073: * inspected or set using the <code>getOperationRegistry()</code> and
0074: * <code>setOperationRegistry()</code> methods. Only experienced
0075: * users should attempt to set the registry. This registry is used to
0076: * map protocol names into either a <code>RemoteRIF</code> or a
0077: * <code>RemoteCRIF</code>.
0078: *
0079: * <p> The <code>TileCache</code> associated with an instance may be
0080: * similarly accessed.
0081: *
0082: * <p> Each instance of <code>RemoteJAI</code> contains a set of
0083: * default rendering hints which will be used for all image creations.
0084: * These hints are merged with any hints supplied to the
0085: * <code>create</code> method; directly supplied hints take precedence
0086: * over the common hints. When a new <code>RemoteJAI</code> instance is
0087: * constructed, its hints are initialized to a copy of the default
0088: * hints. Thus when an instance of <code>RemoteJAI</code> is
0089: * constructed, hints for the default registry, tile cache, number of
0090: * retries, and the retry interval are added to the set of common
0091: * rendering hints. Similarly, invoking <code>setOperationRegistry()</code>,
0092: * <code>setTileCache()</code>, <code>setNumRetries()</code> or
0093: * <code>setRetryInterval()</code> on a <code>RemoteJAI</code> instance
0094: * will cause the respective entity to be added to the common rendering
0095: * hints. The hints associated with any instance may be manipulated
0096: * using the <code>getRenderingHints()</code>,
0097: * <code>setRenderingHints()</code>, <and
0098: * <code>clearRenderingHints()</code> methods.
0099: *
0100: * <p> The <code>TileCache</code> to be used by a particular operation
0101: * may be set during construction, or by calling
0102: * the <code>setTileCache()</code> method. This will result in the
0103: * provided tile cache being added to the set of common rendering
0104: * hints.
0105: *
0106: * <p> Network errors are dealt with through the use of retry intervals and
0107: * retries. Retries refers to the maximum number of times a remote operation
0108: * will be retried. The retry interval refers to the amount of time (in
0109: * milliseconds) between two consecutive retries. If errors are encountered
0110: * at each retry and the number of specified retries has been exhausted, a
0111: * <code>RemoteImagingException</code> will be thrown. By default, the
0112: * number of retries is set to five, and the retry interval
0113: * is set to a thousand milliseconds. These values can be changed by using
0114: * the <code>setNumRetries()</code> and the <code>setRetryInterval</code>
0115: * methods and can also be specified via the <code>RenderingHints</code>
0116: * object passed as an argument to <code>RemoteJAI.create()</code>. Time
0117: * outs (When the amount of time taken to get a response or
0118: * the result of an operation from the remote machine exceeds a limit) are
0119: * not dealt with, and must be taken care of by the network imaging
0120: * protocol implementation itself. The implementation must be responsible
0121: * for monitoring time outs, but on encountering one can deal with it by
0122: * throwing a <code>RemoteImagingException</code>, which will then be dealt
0123: * with using retries and retry intervals.
0124: *
0125: * <p> This class provides the capability of negotiating capabilities
0126: * between the client and the server. The <code>negotiate</code>
0127: * method uses the preferences specified via the
0128: * <code>setNegotiationPreferences</code> method alongwith the server
0129: * and client capabilities retrieved via the <code>getServerCapabilities</code>
0130: * and <code>getClientCapabilities</code> respectively to negotiate on each
0131: * of the preferences. This negotiation treats the client and server
0132: * capabilities as being non-preferences, and the user set
0133: * <code>NegotiableCapabilitySet</code> as being a preference. The
0134: * negotiation is performed according to the rules described in the class
0135: * documentation for <code>NegotiableCapability</code>.
0136: *
0137: * <p> Note that negotiation preferences can be set either prior to
0138: * specifying a particular rendered or renderable operation (by using
0139: * <code>RemoteJAI.create()</code> or
0140: * <code>RemoteJAI.createRenderable()</code>) or afterwards. The currently
0141: * set negotiation preferences are passed to the <code>RemoteRenderedOp</code>
0142: * on its construction through the <code>RenderingHints</code> using the
0143: * <code>KEY_NEGOTIATION_PREFERENCES</code> key. Since
0144: * <code>RemoteRenderableOp</code> does not accept a
0145: * <code>RenderingHints</code> object as a construction argument, the newly
0146: * created <code>RemoteRenderableOp</code> is informed of these preferences
0147: * using it's <code>setRenderingHints()</code> method. These preferences
0148: * can be changed after the construction using the
0149: * <code>setNegotiationPreferences()</code> method on both
0150: * <code>RemoteRenderedOp</code> and <code>RemoteRenderableOp</code>.
0151: *
0152: * The same behavior applies to the number of retries and the retry interval,
0153: * whether they be the default values contained in the default
0154: * <code>RenderingHints</code> or whether they are set using the
0155: * <code>setNumRetries</code> or <code>setRetryInterval</code> methods, the
0156: * existing values are passed to <code>RemoteRenderedOp</code>'s when they
0157: * are created through the <code>RenderingHints</code> argument, and are set
0158: * on the newly created <code>RemoteRenderableOp</code> using the
0159: * <code>setNumRetries</code> or <code>setRetryInterval</code> methods on
0160: * <code>RemoteRenderableOp</code>.
0161: *
0162: * @see JAI
0163: * @see JAIRMIDescriptor
0164: * @see RemoteImagingException
0165: *
0166: * @since JAI 1.1
0167: */
0168: public class RemoteJAI {
0169:
0170: /** The String representing the remote server machine. */
0171: protected String serverName;
0172:
0173: /** The name of the protocol used for client-server communication. */
0174: protected String protocolName;
0175:
0176: /** The OperationRegistry instance used for instantiating operations. */
0177: private OperationRegistry operationRegistry = JAI
0178: .getDefaultInstance().getOperationRegistry();
0179:
0180: /** The amount of time to wait between retries (in Millseconds). */
0181: public static final int DEFAULT_RETRY_INTERVAL = 1000;
0182:
0183: /** The default number of retries. */
0184: public static final int DEFAULT_NUM_RETRIES = 5;
0185:
0186: /**
0187: * Time in milliseconds between retries, initialized to default value.
0188: */
0189: private int retryInterval = DEFAULT_RETRY_INTERVAL; // Milliseconds
0190:
0191: /** The number of retries, initialized to default value. */
0192: private int numRetries = DEFAULT_NUM_RETRIES;
0193:
0194: /** A reference to a centralized TileCache object. */
0195: private transient TileCache cache = JAI.getDefaultInstance()
0196: .getTileCache();
0197:
0198: /**
0199: * The RenderingHints object used to retrieve the TileCache,
0200: * OperationRegistry hints.
0201: */
0202: private RenderingHints renderingHints;
0203:
0204: /**
0205: * The set of preferences to be used for the communication between
0206: * the client and the server.
0207: */
0208: private NegotiableCapabilitySet preferences = null;
0209:
0210: /**
0211: * The set of properties agreed upon after the negotiation process
0212: * between the client and the server has been completed.
0213: */
0214: private static NegotiableCapabilitySet negotiated;
0215:
0216: /** The client and server capabilities. */
0217: private NegotiableCapabilitySet serverCapabilities = null;
0218: private NegotiableCapabilitySet clientCapabilities = null;
0219:
0220: /**
0221: * A Hashtable containing OperationDescriptors hashed by their
0222: * operation names.
0223: */
0224: private Hashtable odHash = null;
0225:
0226: /** The array of descriptors supported by the server. */
0227: private OperationDescriptor descriptors[] = null;
0228:
0229: /** Required to I18N compound messages. */
0230: private static MessageFormat formatter;
0231:
0232: /**
0233: * Constructs a <code>RemoteJAI</code> instance with the given
0234: * protocol name and server name. The semantics of the serverName
0235: * are defined by the particular protocol used to create this
0236: * class. Instructions on how to create a serverName that is
0237: * compatible with this protocol can be retrieved from the
0238: * <code>getServerNameDocs()</code> method on the
0239: * <code>RemoteDescriptor</code> associated with the given
0240: * protocolName. An <code>IllegalArgumentException</code> may
0241: * be thrown by the protocol specific classes at a later point, if
0242: * null is provided as the serverName argument and null is not
0243: * considered a valid serverName by the specified protocol.
0244: *
0245: * @param protocolName The <code>String</code> that identifies the
0246: * remote imaging protocol.
0247: * @param serverName The <code>String</code> that identifies the server.
0248: *
0249: * @throws IllegalArgumentException if protocolName is null.
0250: */
0251: public RemoteJAI(String protocolName, String serverName) {
0252: this (protocolName, serverName, null, null);
0253: }
0254:
0255: /**
0256: * Constructs a <code>RemoteJAI</code> instance with the given
0257: * protocol name, server name, <code>OperationRegistry</code>
0258: * and <code>TileCache</code>. If the specified
0259: * <code>OperationRegistry</code> is null, the registry associated
0260: * with the default <code>JAI</code> instance will be used. If the
0261: * specified <code>TileCache</code> is null, the <code>TileCache</code>
0262: * associated with the default <code>JAI</code> instance will be used.
0263: *
0264: * <p> An <code>IllegalArgumentException</code> may
0265: * be thrown by the protocol specific classes at a later point, if
0266: * null is provided as the serverName argument and null is not
0267: * considered a valid serverName by the specified protocol.
0268: *
0269: * @param serverName The <code>String</code> that identifies
0270: * the server.
0271: * @param protocolName The <code>String</code> that identifies
0272: * the remote imaging protocol.
0273: * @param operationRegistry The <code>OperationRegistry</code> associated
0274: * with this class, if null, default will be used.
0275: * @param tileCache The <code>TileCache</code> associated with
0276: * this class, if null, default will be used.
0277: * @throws IllegalArgumentException if protocolName is null.
0278: */
0279: public RemoteJAI(String protocolName, String serverName,
0280: OperationRegistry registry, TileCache tileCache) {
0281:
0282: if (protocolName == null) {
0283: throw new IllegalArgumentException(JaiI18N
0284: .getString("Generic1"));
0285: }
0286:
0287: // For formatting error strings.
0288: formatter = new MessageFormat("");
0289: formatter.setLocale(Locale.getDefault());
0290:
0291: this .protocolName = protocolName;
0292: this .serverName = serverName;
0293:
0294: // operationRegistry and cache variables are already initialized
0295: // via static initializers, so change them only if the user has
0296: // provided a non-null value for them.
0297: if (registry != null) {
0298: this .operationRegistry = registry;
0299: }
0300:
0301: if (tileCache != null) {
0302: this .cache = tileCache;
0303: }
0304:
0305: this .renderingHints = new RenderingHints(null);
0306: this .renderingHints.put(JAI.KEY_OPERATION_REGISTRY,
0307: operationRegistry);
0308: this .renderingHints.put(JAI.KEY_TILE_CACHE, cache);
0309: this .renderingHints.put(JAI.KEY_RETRY_INTERVAL, new Integer(
0310: retryInterval));
0311: this .renderingHints.put(JAI.KEY_NUM_RETRIES, new Integer(
0312: numRetries));
0313: }
0314:
0315: /**
0316: * Returns a <code>String</code> identifying the remote server machine.
0317: */
0318: public String getServerName() {
0319: return serverName;
0320: }
0321:
0322: /**
0323: * Returns the protocol name.
0324: */
0325: public String getProtocolName() {
0326: return protocolName;
0327: }
0328:
0329: /**
0330: * Sets the amount of time between retries in milliseconds. The
0331: * specified <code>retryInterval</code> parameter will be added
0332: * to the common <code>RenderingHints</code> of this
0333: * <code>RemoteJAI</code> instance, under the
0334: * <code>JAI.KEY_RETRY_INTERVAL</code> key.
0335: *
0336: * @param retryInterval The time interval between retries (milliseconds).
0337: * @throws IllegalArgumentException if retryInterval is negative.
0338: */
0339: public void setRetryInterval(int retryInterval) {
0340:
0341: if (retryInterval < 0) {
0342: throw new IllegalArgumentException(JaiI18N
0343: .getString("Generic3"));
0344: }
0345:
0346: this .retryInterval = retryInterval;
0347: renderingHints.put(JAI.KEY_RETRY_INTERVAL, new Integer(
0348: retryInterval));
0349: }
0350:
0351: /**
0352: * Returns the amount of time between retries in milliseconds.
0353: */
0354: public int getRetryInterval() {
0355: return retryInterval;
0356: }
0357:
0358: /**
0359: * Sets the number of retries. The specified <code>numRetries</code>
0360: * parameter will be added to the common <code>RenderingHints</code>
0361: * of this <code>RemoteJAI</code> instance, under the
0362: * <code>JAI.KEY_NUM_RETRIES</code> key.
0363: *
0364: * @param numRetries The number of retries.
0365: * @throws IllegalArgumentException if numRetries is negative.
0366: */
0367: public void setNumRetries(int numRetries) {
0368: if (numRetries < 0) {
0369: throw new IllegalArgumentException(JaiI18N
0370: .getString("Generic4"));
0371: }
0372:
0373: this .numRetries = numRetries;
0374: renderingHints
0375: .put(JAI.KEY_NUM_RETRIES, new Integer(numRetries));
0376: }
0377:
0378: /**
0379: * Returns the number of retries.
0380: */
0381: public int getNumRetries() {
0382: return numRetries;
0383: }
0384:
0385: /**
0386: * Returns the <code>OperationRegistry</code> being used by this
0387: * <code>RemoteJAI</code> instance.
0388: */
0389: public OperationRegistry getOperationRegistry() {
0390: return operationRegistry;
0391: }
0392:
0393: /**
0394: * Sets the<code>OperationRegistry</code> to be used by this
0395: * <code>RemoteJAI</code> instance. The <code>operationRegistry</code>
0396: * parameter will be added to the <code>RenderingHints</code> of this
0397: * <code>RemoteJAI</code> instance.
0398: *
0399: * @throws IllegalArgumentException if operationRegistry is null.
0400: */
0401: public void setOperationRegistry(OperationRegistry operationRegistry) {
0402: if (operationRegistry == null) {
0403: throw new IllegalArgumentException(JaiI18N
0404: .getString("RemoteJAI4"));
0405: }
0406: this .operationRegistry = operationRegistry;
0407: this .renderingHints.put(JAI.KEY_OPERATION_REGISTRY,
0408: operationRegistry);
0409: }
0410:
0411: /**
0412: * Sets the <code>TileCache</code> to be used by this
0413: * <code>RemoteJAI</code>. The <code>tileCache</code> parameter
0414: * will be added to the <code>RenderingHints</code> of this
0415: * <code>RemoteJAI</code> instance.
0416: *
0417: * @throws IllegalArgumentException if tileCache is null.
0418: */
0419: public void setTileCache(TileCache tileCache) {
0420: if (tileCache == null) {
0421: throw new IllegalArgumentException(JaiI18N
0422: .getString("RemoteJAI5"));
0423: }
0424: this .cache = tileCache;
0425: renderingHints.put(JAI.KEY_TILE_CACHE, cache);
0426: }
0427:
0428: /**
0429: * Returns the <code>TileCache</code> being used by this
0430: * <code>RemoteJAI</code> instance.
0431: */
0432: public TileCache getTileCache() {
0433: return cache;
0434: }
0435:
0436: /**
0437: * Returns the <code>RenderingHints</code> associated with this
0438: * <code>RemoteJAI</code> instance. These rendering hints will be
0439: * merged with any hints supplied as an argument to the
0440: * <code>create()</code> method.
0441: */
0442: public RenderingHints getRenderingHints() {
0443: return renderingHints;
0444: }
0445:
0446: /**
0447: * Sets the <code>RenderingHints</code> associated with this
0448: * <code>RemoteJAI</code> instance. These rendering hints will be
0449: * merged with any hints supplied as an argument to the
0450: * <code>create()</code> method.
0451: *
0452: * @throws IllegalArgumentException if hints is null.
0453: */
0454: public void setRenderingHints(RenderingHints hints) {
0455: if (hints == null) {
0456: throw new IllegalArgumentException(JaiI18N
0457: .getString("RemoteJAI6"));
0458: }
0459: this .renderingHints = hints;
0460: }
0461:
0462: /**
0463: * Clears the <code>RenderingHints</code> associated with this
0464: * <code>RemoteJAI</code> instance.
0465: */
0466: public void clearRenderingHints() {
0467: this .renderingHints = new RenderingHints(null);
0468: }
0469:
0470: /**
0471: * Returns the hint value associated with a given key
0472: * in this <code>RemoteJAI</code> instance, or <code>null</code>
0473: * if no value is associated with the given key.
0474: *
0475: * @throws IllegalArgumentException if key is null.
0476: */
0477: public Object getRenderingHint(RenderingHints.Key key) {
0478: if (key == null) {
0479: throw new IllegalArgumentException(JaiI18N
0480: .getString("RemoteJAI7"));
0481: }
0482: return renderingHints.get(key);
0483: }
0484:
0485: /**
0486: * Sets the hint value associated with a given key
0487: * in this <code>RemoteJAI</code> instance.
0488: *
0489: * @throws IllegalArgumentException if <code>key</code> is
0490: * <code>null</code>.
0491: * @throws IllegalArgumentException if <code>value</code> is
0492: * <code>null</code>.
0493: * @throws IllegalArgumentException if <code>value</code> is
0494: * not of the correct type for the given hint.
0495: */
0496: public void setRenderingHint(RenderingHints.Key key, Object value) {
0497: if (key == null) {
0498: throw new IllegalArgumentException(JaiI18N
0499: .getString("RemoteJAI7"));
0500: }
0501: if (value == null) {
0502: throw new IllegalArgumentException(JaiI18N
0503: .getString("RemoteJAI8"));
0504: }
0505:
0506: try {
0507: renderingHints.put(key, value);
0508: } catch (Exception e) {
0509: throw new IllegalArgumentException(e.toString());
0510: }
0511: }
0512:
0513: /**
0514: * Removes the hint value associated with a given key
0515: * in this <code>RemoteJAI</code> instance.
0516: */
0517: public void removeRenderingHint(RenderingHints.Key key) {
0518: renderingHints.remove(key);
0519: }
0520:
0521: /**
0522: * Creates a <code>RemoteRenderedOp</code> which represents the named
0523: * operation to be performed remotely, using the source(s) and/or
0524: * parameter(s) specified in the <code>ParameterBlock</code>, and
0525: * applying the specified hints to the destination. This method
0526: * should only be used when the final result returned is a single
0527: * <code>RemoteRenderedImage</code>.
0528: *
0529: * <p> The supplied operation name is validated against the
0530: * names of the <code>OperationDescriptor</code>s returned from
0531: * the <code>getServerSupportedOperationList()</code> method. The
0532: * source(s) and/or parameter(s) in the <code>ParameterBlock</code>
0533: * are validated against the named operation's descriptor, both in
0534: * their numbers and types. Additional restrictions placed on the
0535: * sources and parameters by an individual operation are also
0536: * validated by calling its
0537: * <code>OperationDescriptor.validateArguments()</code> method.
0538: *
0539: * <p>Parameters are allowed to have a <code>null</code> input
0540: * value, if that particular parameter has a default value specified
0541: * in its operation's descriptor. In this case, the default value
0542: * will replace the <code>null</code> input.
0543: *
0544: * <p>Unspecified tailing parameters are allowed, if these
0545: * parameters have default values specified in the operation's
0546: * descriptor. However, if a parameter, which has a default value,
0547: * is followed by one or more parameters that
0548: * have no default values, this parameter must be specified in the
0549: * <code>ParameterBlock</code>, even if it only has a value of
0550: * code>null</code>.
0551: *
0552: * <p> The rendering hints associated with this instance of
0553: * <code>RemoteJAI</code> are overlaid with the hints passed to this
0554: * method. That is, the set of keys will be the union of the
0555: * keys from the instance's hints and the hints parameter.
0556: * If the same key exists in both places, the value from the
0557: * hints parameter will be used.
0558: *
0559: * @param opName The name of the operation.
0560: * @param args The source(s) and/or parameter(s) for the operation.
0561: * @param hints The hints for the operation.
0562: *
0563: * @throws IllegalArgumentException if <code>opName</code> is
0564: * <code>null</code>.
0565: * @throws IllegalArgumentException if <code>args</code> is
0566: * <code>null</code>.
0567: * @throws IllegalArgumentException if no
0568: * <code>OperationDescriptor</code> is available from the server
0569: * with the specified operation name.
0570: * @throws IllegalArgumentException if the
0571: * <code>OperationDescriptor</code> for the specified
0572: * operation name on the server does not
0573: * support the "rendered" registry mode.
0574: * @throws IllegalArgumentException if the specified operation does
0575: * not produce a
0576: * <code>java.awt.image.RenderedImage</code>.
0577: * @throws IllegalArgumentException if the specified operation is
0578: * unable to handle the sources and parameters specified in
0579: * <code>args</code>.
0580: *
0581: * @return A <code>RemoteRenderedOp</code> that represents the named
0582: * operation to be performed remotely, or <code>null</code>
0583: * if the specified operation
0584: * is in the "immediate" mode and the rendering of the
0585: * <code>PlanarImage</code> failed.
0586: */
0587: public RemoteRenderedOp create(String opName, ParameterBlock args,
0588: RenderingHints hints) {
0589:
0590: if (opName == null) {
0591: throw new IllegalArgumentException(JaiI18N
0592: .getString("RemoteJAI9"));
0593: }
0594:
0595: if (args == null) {
0596: throw new IllegalArgumentException(JaiI18N
0597: .getString("RemoteJAI10"));
0598: }
0599:
0600: // Initialize the odHash hashtable
0601: getServerSupportedOperationList();
0602:
0603: // Get the OperationDescriptor associated with this name.
0604: OperationDescriptor odesc = (OperationDescriptor) odHash
0605: .get(new CaselessStringKey(opName));
0606:
0607: if (odesc == null) {
0608: throw new IllegalArgumentException(JaiI18N
0609: .getString("RemoteJAI11"));
0610: }
0611:
0612: // Does this operation support rendered mode?
0613: if (!odesc.isModeSupported("rendered")) {
0614: throw new IllegalArgumentException(JaiI18N
0615: .getString("RemoteJAI12"));
0616: }
0617:
0618: // Does the operation produce a RenderedImage?
0619: if (!RenderedImage.class.isAssignableFrom(odesc
0620: .getDestClass("rendered"))) {
0621: throw new IllegalArgumentException(JaiI18N
0622: .getString("RemoteJAI13"));
0623: }
0624:
0625: // Validate input arguments. The ParameterBlock is cloned here
0626: // because OperationDescriptor.validateArguments() may change
0627: // its content.
0628: StringBuffer msg = new StringBuffer();
0629: args = (ParameterBlock) args.clone();
0630: if (!odesc.validateArguments("rendered", args, msg)) {
0631: throw new IllegalArgumentException(msg.toString());
0632: }
0633:
0634: // Merge rendering hints. Hints passed in take precedence.
0635: RenderingHints mergedHints;
0636: if (hints == null) {
0637: mergedHints = renderingHints;
0638: } else if (renderingHints.isEmpty()) {
0639: mergedHints = hints;
0640: } else {
0641: mergedHints = new RenderingHints((Map) renderingHints);
0642: mergedHints.add(hints);
0643: }
0644:
0645: RemoteRenderedOp op = new RemoteRenderedOp(operationRegistry,
0646: protocolName, serverName, opName, args, mergedHints);
0647:
0648: // If the operation requests immediate rendering, do so.
0649: if (odesc.isImmediate()) {
0650: PlanarImage im = null;
0651: im = op.getRendering();
0652:
0653: if (im == null) {
0654: // Op could not be rendered, return null.
0655: return null;
0656: }
0657: }
0658:
0659: // Return the RemoteRenderedOp associated with this operation.
0660: return op;
0661: }
0662:
0663: /**
0664: * Creates a <code>RemoteRenderableOp</code> that represents the named
0665: * operation to be performed remotely, using the source(s) and/or
0666: * parameter(s) specified in the <code>ParameterBlock</code>.
0667: * This method should only be used when the final result returned
0668: * is a single <code>RenderableImage</code>.
0669: *
0670: * <p> The supplied operation name is validated against the names
0671: * of the <code>OperationDescriptor</code>s returned from
0672: * the <code>getServerSupportedOperationList()</code> method.
0673: * The source(s) and/or parameter(s) in the
0674: * <code>ParameterBlock</code> are validated against the named
0675: * operation's descriptor, both in their numbers and types.
0676: * Additional restrictions placed on the sources and parameters
0677: * by an individual operation are also validated by calling its
0678: * <code>OperationDescriptor.validateRenderableArguments()</code>
0679: * method.
0680: *
0681: * <p>Parameters are allowed to have a <code>null</code> input
0682: * value, if that particular parameter has a default value specified
0683: * in its operation's descriptor. In this case, the default value
0684: * will replace the <code>null</code> input.
0685: *
0686: * <p>Unspecified tailing parameters are allowed, if these
0687: * parameters have default values specified in the operation's
0688: * descriptor. However, if a parameter, which
0689: * has a default value, is followed by one or more parameters that
0690: * have no default values, this parameter must be specified in the
0691: * <code>ParameterBlock</code>, even if it only has a value of
0692: * code>null</code>.
0693: *
0694: * @param opName The name of the operation.
0695: * @param args The source(s) and/or parameter(s) for the operation.
0696: *
0697: * @throws IllegalArgumentException if <code>opName</code> is
0698: * <code>null</code>.
0699: * @throws IllegalArgumentException if <code>args</code> is
0700: * <code>null</code>.
0701: * @throws IllegalArgumentException if no
0702: * <code>OperationDescriptor</code> is available from the server
0703: * with the specified operation name.
0704: * @throws IllegalArgumentException if the
0705: * <code>OperationDescriptor</code> for the specified
0706: * operation name on the server does not
0707: * support "renderable" registry mode.
0708: * @throws IllegalArgumentException if the specified operation does
0709: * not produce a
0710: * <code>java.awt.image.renderable.RenderableImage</code>.
0711: * @throws IllegalArgumentException if the specified operation is
0712: * unable to handle the sources and parameters specified in
0713: * <code>args</code>.
0714: *
0715: * @return A <code>RemoteRenderableOp</code> that represents the named
0716: * operation to be performed remotely.
0717: */
0718: public RemoteRenderableOp createRenderable(String opName,
0719: ParameterBlock args) {
0720:
0721: if (opName == null) {
0722: throw new IllegalArgumentException(JaiI18N
0723: .getString("RemoteJAI9"));
0724: }
0725:
0726: if (args == null) {
0727: throw new IllegalArgumentException(JaiI18N
0728: .getString("RemoteJAI10"));
0729: }
0730:
0731: // Initialize the odHash hashtable
0732: getServerSupportedOperationList();
0733:
0734: // Get the OperationDescriptor associated with this name.
0735: OperationDescriptor odesc = (OperationDescriptor) odHash
0736: .get(new CaselessStringKey(opName));
0737:
0738: if (odesc == null) {
0739: throw new IllegalArgumentException(JaiI18N
0740: .getString("RemoteJAI11"));
0741: }
0742:
0743: // Does this operation support rendered mode?
0744: if (!odesc.isModeSupported("renderable")) {
0745: throw new IllegalArgumentException(JaiI18N
0746: .getString("RemoteJAI14"));
0747: }
0748:
0749: // Does the operation produce a RenderedImage?
0750: if (!RenderableImage.class.isAssignableFrom(odesc
0751: .getDestClass("renderable"))) {
0752: throw new IllegalArgumentException(JaiI18N
0753: .getString("RemoteJAI15"));
0754: }
0755:
0756: // Validate input arguments. The ParameterBlock is cloned here
0757: // because OperationDescriptor.validateRenderableArguments()
0758: // may change its content.
0759: StringBuffer msg = new StringBuffer();
0760: args = (ParameterBlock) args.clone();
0761: if (!odesc.validateArguments("renderable", args, msg)) {
0762: throw new IllegalArgumentException(msg.toString());
0763: }
0764:
0765: RemoteRenderableOp op = new RemoteRenderableOp(
0766: operationRegistry, protocolName, serverName, opName,
0767: args);
0768: // Set the node-scope hints
0769: op.setRenderingHints(renderingHints);
0770:
0771: // Return the RemoteRenderableOp.
0772: return op;
0773: }
0774:
0775: //
0776: // NEGOTIATION RELATED METHODS
0777: //
0778:
0779: /**
0780: * Sets the preferences to be used in the client-server
0781: * communication. These preferences are utilized in the negotiation
0782: * process. Note that preferences for more than one category can be
0783: * specified using this method since <code>NegotiableCapabilitySet</code>
0784: * allows different <code>NegotiableCapability</code> objects to be
0785: * bundled up in one <code>NegotiableCapabilitySet</code> class. Even
0786: * under the same category (as specified by the getCategory() method
0787: * on <code>NegotiableCapability</code>), multiple
0788: * <code>NegotiableCapability</code> objects can be added to the
0789: * preferences. The preference added first for a particular category is
0790: * given highest priority in the negotiation process.
0791: *
0792: * <p> Since a new set of preferences is set everytime this method is
0793: * called, this method allows for changing negotiation preferences
0794: * multiple times. However it should be noted that preferences set on
0795: * this method are relevant only prior to the creation of an
0796: * operation (using the <code>RemoteJAI.create</code> method). To
0797: * change negotiation preferences on an operation after it has been
0798: * created, the <code>setNegotiationPreferences()</code> method on the
0799: * created <code>RemoteRenderedOp</code> should be used. The
0800: * <code>preferences</code> parameter will be added to the
0801: * <code>RenderingHints</code> of this <code>RemoteJAI</code> instance.
0802: */
0803: public void setNegotiationPreferences(
0804: NegotiableCapabilitySet preferences) {
0805:
0806: this .preferences = preferences;
0807:
0808: if (preferences == null)
0809: renderingHints.remove(JAI.KEY_NEGOTIATION_PREFERENCES);
0810: else
0811: renderingHints.put(JAI.KEY_NEGOTIATION_PREFERENCES,
0812: preferences);
0813:
0814: // Every time new preferences are set, invalidate old Negotiation
0815: // results and do the negotiation again.
0816: negotiated = null;
0817: getNegotiatedValues();
0818: }
0819:
0820: /**
0821: * Returns the results of the negotiation between the client and server
0822: * capabilities according to the user preferences specified at an
0823: * earlier time. This will return null if the negotiation failed.
0824: *
0825: * <p> If a negotiation cycle has not been initiated prior to calling
0826: * this method, or the negotiation preferences have been
0827: * changed, this method will initiate a new negotiation cycle, which will
0828: * create and return a new set of negotiated values.
0829: *
0830: * @returns A <code>NegotiableCapabilitySet</code> that is the
0831: * result of the negotiation process, if negotiation is successful,
0832: * otherwise returns null.
0833: */
0834: public NegotiableCapabilitySet getNegotiatedValues()
0835: throws RemoteImagingException {
0836:
0837: // If negotiation was not performed before, or if new preferences
0838: // have invalidated the old negotiated results.
0839: if (negotiated == null) {
0840:
0841: if (serverCapabilities == null) {
0842: serverCapabilities = getServerCapabilities();
0843: }
0844:
0845: if (clientCapabilities == null) {
0846: clientCapabilities = getClientCapabilities();
0847: }
0848:
0849: // Do the negotiation
0850: negotiated = negotiate(preferences, serverCapabilities,
0851: clientCapabilities);
0852: }
0853:
0854: return negotiated;
0855: }
0856:
0857: /**
0858: * Returns the results of the negotiation between the client and server
0859: * capabilities according to the user preferences specified at an
0860: * earlier time for the given category. This method returns a
0861: * <code>NegotiableCapability</code> object, that represents the result
0862: * of the negotiation for the given category. If the negotiation failed,
0863: * null will be returned.
0864: *
0865: * <p> If a negotiation cycle has not been initiated prior to calling
0866: * this method, or the negotiation preferences have been
0867: * changed, this method will initiate a new negotiation cycle, which will
0868: * create and return a new negotiated value for the given category.
0869: *
0870: * @param category The category to negotiate on.
0871: * @throws IllegalArgumentException if category is null.
0872: * @returns A <code>NegotiableCapabilitySet</code> that is the
0873: * result of the negotiation process, if negotiation is successful,
0874: * otherwise returns null.
0875: */
0876: public NegotiableCapability getNegotiatedValues(String category)
0877: throws RemoteImagingException {
0878:
0879: // We do not need to check for category being null, since that
0880: // check will be made by the methods called from within this method.
0881:
0882: // If negotiation was not performed before, or if new preferences
0883: // have invalidated the old negotiated results.
0884: if (negotiated == null) {
0885:
0886: if (serverCapabilities == null) {
0887: serverCapabilities = getServerCapabilities();
0888: }
0889:
0890: if (clientCapabilities == null) {
0891: clientCapabilities = getClientCapabilities();
0892: }
0893:
0894: // Do the negotiation
0895: return negotiate(preferences, serverCapabilities,
0896: clientCapabilities, category);
0897: } else {
0898: // If negotiated is not null, then the negotiated results are
0899: // current and the result for the given category can just be
0900: // extracted from there and returned.
0901: return negotiated.getNegotiatedValue(category);
0902: }
0903: }
0904:
0905: /**
0906: * This method negotiates the capabilities to be used in the remote
0907: * communication. Upon completion of the negotiation process,
0908: * this method returns a <code>NegotiableCapabilitySet</code> which
0909: * contains an aggregation of the <code>NegotiableCapability</code>
0910: * objects that represent the results of negotiation. If the negotiation
0911: * fails, null will be returned.
0912: *
0913: * <p> The negotiation process treats the serverCapabilities and the
0914: * clientCapabilities as non-preferences and will throw an
0915: * <code>IllegalArgumentException</code> if the
0916: * <code>isPreference</code> method for either of these returns
0917: * true. The preferences <code>NegotiableCapabilitySet</code> should
0918: * return true from its <code>isPreference</code> method, otherwise an
0919: * <code>IllegalArgumentException</code> will be thrown. The negotiation
0920: * is done in accordance with the rules described in the class comments
0921: * for <code>NegotiableCapability</code>.
0922: *
0923: * <p> If either the serverCapabilities or the clientCapabilities
0924: * is null, then the negotiation will fail, and null will be returned.
0925: * If preferences is null, the negotiation will become a two-way
0926: * negotiation between the two non-null
0927: * <code>NegotiableCapabilitySet</code>s.
0928: *
0929: * @param preferences The user preferences for the negotiation.
0930: * @param serverCapabilities The capabilities of the server.
0931: * @param clientCapabilities The capabilities of the client.
0932: *
0933: * @throws IllegalArgumentException if serverCapabilities is a
0934: * preference, i.e., if it's <code>isPreference()</code> method
0935: * returns true.
0936: * @throws IllegalArgumentException if clientCapabilities is a
0937: * preference, i.e., if it's <code>isPreference()</code> method
0938: * returns true.
0939: * @throws IllegalArgumentException if preferences is a
0940: * non-preference, i.e., if it's <code>isPreference()</code> method
0941: * returns false.
0942: */
0943: public static NegotiableCapabilitySet negotiate(
0944: NegotiableCapabilitySet preferences,
0945: NegotiableCapabilitySet serverCapabilities,
0946: NegotiableCapabilitySet clientCapabilities) {
0947:
0948: if (serverCapabilities == null || clientCapabilities == null)
0949: return null;
0950:
0951: if (serverCapabilities != null
0952: && serverCapabilities.isPreference() == true)
0953: throw new IllegalArgumentException(JaiI18N
0954: .getString("RemoteJAI20"));
0955:
0956: if (clientCapabilities != null
0957: && clientCapabilities.isPreference() == true)
0958: throw new IllegalArgumentException(JaiI18N
0959: .getString("RemoteJAI21"));
0960:
0961: if (preferences == null) {
0962: return serverCapabilities.negotiate(clientCapabilities);
0963: } else {
0964: if (preferences.isPreference() == false)
0965: throw new IllegalArgumentException(JaiI18N
0966: .getString("RemoteJAI19"));
0967:
0968: NegotiableCapabilitySet clientServerCap = serverCapabilities
0969: .negotiate(clientCapabilities);
0970: if (clientServerCap == null)
0971: return null;
0972: return clientServerCap.negotiate(preferences);
0973: }
0974: }
0975:
0976: /**
0977: * This method negotiates the capabilities to be used in the remote
0978: * communication for the given category. Upon completion of the
0979: * negotiation process, this method returns a
0980: * <code>NegotiableCapability</code> object, that represents the result
0981: * of the negotiation for the given category. If the negotiation fails,
0982: * null will be returned.
0983: *
0984: * <p> The negotiation process treats the serverCapabilities and the
0985: * clientCapabilities as non-preferences and will throw an
0986: * <code>IllegalArgumentException</code> if the
0987: * <code>isPreference</code> method for either of these returns
0988: * true. The preferences <code>NegotiableCapabilitySet</code> should
0989: * return true from its <code>isPreference</code> method or an
0990: * <code>IllegalArgumentException</code> will be thrown. The negotiation
0991: * is done in accordance with the rules described in the class comments
0992: * for <code>NegotiableCapability</code>.
0993: *
0994: * <p> If either the serverCapabilities or the clientCapabilities
0995: * is null, then the negotiation will fail, and null will be returned.
0996: * If preferences is null, the negotiation will become a two-way
0997: * negotiation between the two non-null
0998: * <code>NegotiableCapabilitySet</code>s.
0999: *
1000: * @param preferences The user preferences for the negotiation.
1001: * @param serverCapabilities The capabilities of the server.
1002: * @param clientCapabilities The capabilities of the client.
1003: * @param category The category to perform the negotiation on.
1004: *
1005: * @throws IllegalArgumentException if preferences is a
1006: * non-preference, i.e., if it's <code>isPreference()</code> method
1007: * returns false.
1008: * @throws IllegalArgumentException if serverCapabilities is a
1009: * preference, i.e., if it's <code>isPreference()</code> method
1010: * returns true.
1011: * @throws IllegalArgumentException if clientCapabilities is a
1012: * preference, i.e., if it's <code>isPreference()</code> method
1013: * returns true.
1014: * @throws IllegalArgumentException if category is null.
1015: */
1016: public static NegotiableCapability negotiate(
1017: NegotiableCapabilitySet preferences,
1018: NegotiableCapabilitySet serverCapabilities,
1019: NegotiableCapabilitySet clientCapabilities, String category) {
1020:
1021: if (serverCapabilities == null || clientCapabilities == null)
1022: return null;
1023:
1024: if (serverCapabilities != null
1025: && serverCapabilities.isPreference() == true)
1026: throw new IllegalArgumentException(JaiI18N
1027: .getString("RemoteJAI20"));
1028:
1029: if (clientCapabilities != null
1030: && clientCapabilities.isPreference() == true)
1031: throw new IllegalArgumentException(JaiI18N
1032: .getString("RemoteJAI21"));
1033:
1034: if (preferences != null && preferences.isPreference() == false)
1035: throw new IllegalArgumentException(JaiI18N
1036: .getString("RemoteJAI19"));
1037:
1038: if (category == null)
1039: throw new IllegalArgumentException(JaiI18N
1040: .getString("RemoteJAI26"));
1041:
1042: if (preferences == null || preferences.isEmpty()) {
1043: return serverCapabilities.getNegotiatedValue(
1044: clientCapabilities, category);
1045: } else {
1046:
1047: List prefList = preferences.get(category);
1048: List serverList = serverCapabilities.get(category);
1049: List clientList = clientCapabilities.get(category);
1050: Iterator p = prefList.iterator();
1051:
1052: NegotiableCapability server, client, result;
1053:
1054: NegotiableCapability pref = null;
1055: //If there are no preferences for the current category
1056: if (p.hasNext() == false)
1057: pref = null;
1058: else
1059: pref = (NegotiableCapability) p.next();
1060:
1061: Vector results = new Vector();
1062:
1063: // Negotiate every server NC with every client NC
1064: for (Iterator s = serverList.iterator(); s.hasNext();) {
1065: server = (NegotiableCapability) s.next();
1066: for (Iterator c = clientList.iterator(); c.hasNext();) {
1067: client = (NegotiableCapability) c.next();
1068:
1069: result = server.negotiate(client);
1070: if (result == null) {
1071: // This negotiation failed, continue to the next one
1072: continue;
1073: } else {
1074: // Negotiation between client and server succeeded,
1075: // add to results array
1076: results.add(result);
1077:
1078: if (pref != null) {
1079: // Negotiate with the pref, if negotiation is
1080: // successful, return the result from this method.
1081: result = result.negotiate(pref);
1082: }
1083:
1084: if (result != null) {
1085: return result;
1086: } // else move onto next negotiation
1087: }
1088: }
1089: }
1090:
1091: for (; p.hasNext();) {
1092: pref = (NegotiableCapability) p.next();
1093: for (int r = 0; r < results.size(); r++) {
1094: if ((result = pref
1095: .negotiate((NegotiableCapability) results
1096: .elementAt(r))) != null) {
1097: return result;
1098: }
1099: }
1100: }
1101:
1102: // If all negotiations failed, return null.
1103: return null;
1104: }
1105: }
1106:
1107: /**
1108: * Returns the set of capabilites supported by the server. If any
1109: * network related errors are encountered by this method (identified
1110: * as such by receiving a <code>RemoteImagingException</code>), they
1111: * will be dealt with by the use of retries and retry intervals.
1112: */
1113: public NegotiableCapabilitySet getServerCapabilities()
1114: throws RemoteImagingException {
1115:
1116: if (serverCapabilities == null) {
1117:
1118: // Get the RemoteDescriptor for protocolName
1119: RemoteDescriptor descriptor = (RemoteDescriptor) operationRegistry
1120: .getDescriptor(RemoteDescriptor.class, protocolName);
1121:
1122: if (descriptor == null) {
1123: Object[] msgArg0 = { new String(protocolName) };
1124: formatter
1125: .applyPattern(JaiI18N.getString("RemoteJAI16"));
1126: throw new RuntimeException(formatter.format(msgArg0));
1127: }
1128: Exception rieSave = null;
1129: int count = 0;
1130: while (count++ < numRetries) {
1131: try {
1132: serverCapabilities = descriptor
1133: .getServerCapabilities(serverName);
1134: break;
1135: } catch (RemoteImagingException rie) {
1136: // Print that an Exception occured
1137: System.err
1138: .println(JaiI18N.getString("RemoteJAI24"));
1139: rieSave = rie;
1140: // Sleep for retryInterval milliseconds
1141: try {
1142: Thread.sleep(retryInterval);
1143: } catch (InterruptedException ie) {
1144: sendExceptionToListener(JaiI18N
1145: .getString("Generic5"),
1146: new ImagingException(JaiI18N
1147: .getString("Generic5"), ie));
1148: // throw new RuntimeException(ie.toString());
1149: }
1150: }
1151: }
1152:
1153: if (serverCapabilities == null && count > numRetries) {
1154: sendExceptionToListener(JaiI18N
1155: .getString("RemoteJAI18"), rieSave);
1156: // throw new RemoteImagingException(
1157: // JaiI18N.getString("RemoteJAI18")+"\n"+rieSave.getMessage());
1158: }
1159: }
1160:
1161: return serverCapabilities;
1162: }
1163:
1164: /**
1165: * Returns the set of capabilities supported by the client.
1166: */
1167: public NegotiableCapabilitySet getClientCapabilities() {
1168:
1169: if (clientCapabilities == null) {
1170:
1171: RemoteRIF rrif = (RemoteRIF) operationRegistry.getFactory(
1172: "remoteRendered", protocolName);
1173: if (rrif == null) {
1174: rrif = (RemoteRIF) operationRegistry.getFactory(
1175: "remoteRenderable", protocolName);
1176: }
1177:
1178: if (rrif == null) {
1179: Object[] msgArg0 = { new String(protocolName) };
1180: formatter
1181: .applyPattern(JaiI18N.getString("RemoteJAI17"));
1182: throw new RuntimeException(formatter.format(msgArg0));
1183: }
1184:
1185: clientCapabilities = rrif.getClientCapabilities();
1186: }
1187:
1188: return clientCapabilities;
1189: }
1190:
1191: /**
1192: * Returns the list of <code>OperationDescriptor</code>s that describe
1193: * the operations supported by the server. If any
1194: * network related errors are encountered by this method (identified
1195: * as such by receiving a <code>RemoteImagingException</code>), they
1196: * will be dealt with by the use of retries and retry intervals.
1197: */
1198: public OperationDescriptor[] getServerSupportedOperationList()
1199: throws RemoteImagingException {
1200:
1201: if (descriptors == null) {
1202:
1203: // Get the RemoteDescriptor for protocolName
1204: RemoteDescriptor descriptor = (RemoteDescriptor) operationRegistry
1205: .getDescriptor(RemoteDescriptor.class, protocolName);
1206:
1207: if (descriptor == null) {
1208: Object[] msgArg0 = { new String(protocolName) };
1209: formatter
1210: .applyPattern(JaiI18N.getString("RemoteJAI16"));
1211: throw new RuntimeException(formatter.format(msgArg0));
1212: }
1213: Exception rieSave = null;
1214: int count = 0;
1215: while (count++ < numRetries) {
1216: try {
1217: descriptors = descriptor
1218: .getServerSupportedOperationList(serverName);
1219: break;
1220: } catch (RemoteImagingException rie) {
1221: // Print that an Exception occured
1222: System.err
1223: .println(JaiI18N.getString("RemoteJAI25"));
1224: rieSave = rie;
1225: // Sleep for retryInterval milliseconds
1226: try {
1227: Thread.sleep(retryInterval);
1228: } catch (InterruptedException ie) {
1229: // throw new ImagingException(ie);
1230: sendExceptionToListener(JaiI18N
1231: .getString("Generic5"),
1232: new ImagingException(JaiI18N
1233: .getString("Generic5"), ie));
1234: }
1235: }
1236: }
1237:
1238: if (descriptors == null && count > numRetries) {
1239: sendExceptionToListener(JaiI18N
1240: .getString("RemoteJAI23"), rieSave);
1241: // throw new RemoteImagingException(
1242: // JaiI18N.getString("RemoteJAI23")+"\n"+rieSave.getMessage());
1243: }
1244:
1245: // Store the descriptors into a Hashtable hashed by
1246: // their operation name.
1247: odHash = new Hashtable();
1248: for (int i = 0; i < descriptors.length; i++) {
1249: odHash.put(new CaselessStringKey(descriptors[i]
1250: .getName()), descriptors[i]);
1251: }
1252: }
1253:
1254: return descriptors;
1255: }
1256:
1257: void sendExceptionToListener(String message, Exception e) {
1258: ImagingListener listener = JAI.getDefaultInstance()
1259: .getImagingListener();
1260: listener.errorOccurred(message, e, this , false);
1261: }
1262: }
|