Source Code Cross Referenced for SerializableRenderedImage.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » javax » media » jai » remote » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » javax.media.jai.remote 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: SerializableRenderedImage.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.1 $
0009:         * $Date: 2005/02/11 04:57:53 $
0010:         * $State: Exp $
0011:         */
0012:        package javax.media.jai.remote;
0013:
0014:        /*
0015:         XXX: RFE (from Bob):
0016:         If the SM can't be serialized perhaps a different SM know to be serializable
0017:         could be created and the data copied.
0018:         */
0019:
0020:        import java.awt.Image;
0021:        import java.awt.Point;
0022:        import java.awt.Rectangle;
0023:        import java.awt.image.ColorModel;
0024:        import java.awt.image.DataBuffer;
0025:        import java.awt.image.Raster;
0026:        import java.awt.image.RenderedImage;
0027:        import java.awt.image.SampleModel;
0028:        import java.awt.image.WritableRaster;
0029:        import java.io.ByteArrayInputStream;
0030:        import java.io.ByteArrayOutputStream;
0031:        import java.io.InputStream;
0032:        import java.io.InterruptedIOException;
0033:        import java.io.IOException;
0034:        import java.io.NotSerializableException;
0035:        import java.io.OutputStream;
0036:        import java.io.ObjectInputStream;
0037:        import java.io.ObjectOutputStream;
0038:        import java.io.Serializable;
0039:        import java.net.InetAddress;
0040:        import java.net.Socket;
0041:        import java.net.SocketException;
0042:        import java.net.ServerSocket;
0043:        import java.net.UnknownHostException;
0044:        import java.util.Enumeration;
0045:        import java.util.Hashtable;
0046:        import java.util.Vector;
0047:        import javax.media.jai.JAI;
0048:        import javax.media.jai.OperationRegistry;
0049:        import javax.media.jai.PlanarImage;
0050:        import javax.media.jai.ParameterListDescriptor;
0051:        import javax.media.jai.RasterAccessor;
0052:        import javax.media.jai.RasterFormatTag;
0053:        import javax.media.jai.RemoteImage;
0054:        import javax.media.jai.TileCache;
0055:        import javax.media.jai.remote.SerializableState;
0056:        import javax.media.jai.remote.SerializerFactory;
0057:        import javax.media.jai.tilecodec.TileCodecDescriptor;
0058:        import javax.media.jai.tilecodec.TileCodecParameterList;
0059:        import javax.media.jai.tilecodec.TileDecoder;
0060:        import javax.media.jai.tilecodec.TileDecoderFactory;
0061:        import javax.media.jai.tilecodec.TileEncoder;
0062:        import javax.media.jai.tilecodec.TileEncoderFactory;
0063:        import javax.media.jai.util.CaselessStringKey;
0064:        import javax.media.jai.util.ImagingException;
0065:        import javax.media.jai.util.ImagingListener;
0066:        import com.sun.media.jai.util.ImageUtil;
0067:
0068:        /**
0069:         * A serializable wrapper class for classes which implement the
0070:         * <code>RenderedImage</code> interface.
0071:         *
0072:         * <p> A <code>SerializableRenderedImage</code> provides a means to serialize
0073:         * a <code>RenderedImage</code>.  Transient fields are handled using
0074:         * <code>Serializer</code>s registered with <code>SerializerFactory</code>.
0075:         * Two means are available for providing the wrapped
0076:         * <code>RenderedImage</code> data to a remote version of a
0077:         * <code>SerializableRenderedImage</code> object: either via deep copy or by
0078:         * "on-demand" copying.  If a deep copy is requested, the entire image
0079:         * <code>Raster</code> is copied during object serialization and tiles are
0080:         * extracted from it as needed using the <code>Raster.createChild()</code>
0081:         * method.  If a deep copy is not used, the image data are transmitted
0082:         * "on-demand" using socket communications.  If the request is made on the
0083:         * local host, the image data are provided in both cases merely by forwarding
0084:         * the request to the wrapped <code>RenderedImage</code>.  Note that a single
0085:         * <code>SerializableRenderedImage</code> object should be able to service
0086:         * multiple remote hosts.
0087:         *
0088:         * <p> The properties associated with the <code>RenderedImage</code> being 
0089:         * wrapped are serialized and accessible to a remote version of a
0090:         * <code>SerializableRenderedImage</code> object. However it should be noted
0091:         * that only those properties which are serializable are available to the
0092:         * <code>SerializableRenderedImage</code> object.
0093:         *
0094:         * <p> This class makes no guarantee as to the stability of the data of the
0095:         * wrapped image, at least in the case where a deep copy is not made.
0096:         * Consequently if the data of a <code>RenderedImage</code> change but
0097:         * affected tiles have already been transmitted then the modifications will
0098:         * not be visible remotely.  For example, this implies that a
0099:         * <code>SerializableRenderedImage</code> should not be used to wrap a
0100:         * <code>RenderedOp</code> the data of which are subject to change if the
0101:         * chain in which the node is present is edited.  Instead the
0102:         * <code>SerializableRenderedImage</code> should be used to wrap the image
0103:         * returned by invoking either <code>getRendering()</code> or
0104:         * <code>createInstance()</code> on the <code>RenderedOp</code>.  A similar
0105:         * situation will obtain if the wrapped image is a
0106:         * <code>WritableRenderedImage</code>.  If in this case the wrapped image
0107:         * is also a <code>PlanarImage</code>, then the image returned by
0108:         * <code>createSnapshot()</code> should be wrapped instead.
0109:         *
0110:         * <p> An example of the usage of this class is as follows:
0111:         *
0112:         * <pre>
0113:         * import java.io.IOException;
0114:         * import java.io.ObjectInputStream;
0115:         * import java.io.ObjectOutputStream;
0116:         * import java.io.Serializable;
0117:         *
0118:         * public class SomeSerializableClass implements Serializable {
0119:         *     protected transient RenderedImage image;
0120:         *
0121:         *     // Fields omitted.
0122:         *
0123:         *     public SomeSerializableClass(RenderedImage image) {
0124:         *         this.image = image;
0125:         *     }
0126:         *
0127:         *     // Methods omitted.
0128:         *
0129:         *     // Serialization method.
0130:         *     private void writeObject(ObjectOutputStream out) throws IOException {
0131:         *         out.defaultWriteObject();
0132:         *         out.writeObject(new SerializableRenderedImage(image));
0133:         *     }
0134:         *
0135:         *     // Deserialization method.
0136:         *     private void readObject(ObjectInputStream in)
0137:         *         throws IOException, ClassNotFoundException {
0138:         *         in.defaultReadObject();
0139:         *         image = (RenderedImage)in.readObject();
0140:         *     }
0141:         * }
0142:         * </pre>
0143:         *
0144:         * @see java.awt.image.RenderedImage
0145:         * @see java.awt.image.WritableRenderedImage
0146:         * @see javax.media.jai.PlanarImage
0147:         * @see javax.media.jai.RenderedOp
0148:         *
0149:         *
0150:         * @since JAI 1.1
0151:         */
0152:        // NB: This class was added in EA3 to com.sun.media.jai.rmi and made
0153:        // public only in JAI 1.1.
0154:        public final class SerializableRenderedImage implements  RenderedImage,
0155:                Serializable {
0156:            /** Value to indicate the server socket timeout period (milliseconds). */
0157:            private static final int SERVER_TIMEOUT = 60000; // XXX 1 minute?
0158:
0159:            /** Message indicating that a client will not connect again. */
0160:            private static final String CLOSE_MESSAGE = "CLOSE";
0161:
0162:            /** Message indicating that the server read the client's close message. */
0163:            private static final String CLOSE_ACK = "CLOSE_ACK";
0164:
0165:            /** The unique ID of this image. */
0166:            private Object UID;
0167:
0168:            /** Flag indicating whether this is a data server. */
0169:            private transient boolean isServer;
0170:
0171:            /** Flag indicating whether the source image is a RemoteImage. */
0172:            private boolean isSourceRemote;
0173:
0174:            /** The RenderedImage source of this object (server only). */
0175:            private transient RenderedImage source;
0176:
0177:            /** The X coordinate of the image's upper-left pixel. */
0178:            private int minX;
0179:
0180:            /** The Y coordinate of the image's upper-left pixel. */
0181:            private int minY;
0182:
0183:            /** The image's width in pixels. */
0184:            private int width;
0185:
0186:            /** The image's height in pixels. */
0187:            private int height;
0188:
0189:            /** The horizontal index of the leftmost column of tiles. */
0190:            private int minTileX;
0191:
0192:            /** The vertical index of the uppermost row of tiles. */
0193:            private int minTileY;
0194:
0195:            /** The number of tiles along the tile grid in the horizontal direction. */
0196:            private int numXTiles;
0197:
0198:            /** The number of tiles along the tile grid in the vertical direction. */
0199:            private int numYTiles;
0200:
0201:            /** The width of a tile. */
0202:            private int tileWidth;
0203:
0204:            /** The height of a tile. */
0205:            private int tileHeight;
0206:
0207:            /** The X coordinate of the upper-left pixel of tile (0, 0). */
0208:            private int tileGridXOffset;
0209:
0210:            /** The Y coordinate of the upper-left pixel of tile (0, 0). */
0211:            private int tileGridYOffset;
0212:
0213:            /** The image's SampleModel. */
0214:            private transient SampleModel sampleModel = null;
0215:
0216:            /** The image's ColorModel. */
0217:            private transient ColorModel colorModel = null;
0218:
0219:            /** The image's sources, stored in a Vector. */
0220:            private transient Vector sources = null;
0221:
0222:            /** A Hashtable containing the image properties. */
0223:            private transient Hashtable properties = null;
0224:
0225:            /** Flag indicating whether to use a deep copy of the source image. */
0226:            private boolean useDeepCopy;
0227:
0228:            /** A Rectangle indicating the entire image bounds. */
0229:            private Rectangle imageBounds;
0230:
0231:            /** The entire image Raster (client only). */
0232:            private transient Raster imageRaster;
0233:
0234:            /** The Internet Protocol (IP) address of the instantiating host. */
0235:            private InetAddress host;
0236:
0237:            /** The port on which the data server is listening. */
0238:            private int port;
0239:
0240:            /** Flag indicating that the server is available for connections. */
0241:            private transient boolean serverOpen = false;
0242:
0243:            /** The server socket for image data transfer (server only). */
0244:            private transient ServerSocket serverSocket = null;
0245:
0246:            /** The thread in which the data server is running (server only). */
0247:            private transient Thread serverThread;
0248:
0249:            /** The tile codec format name is TileCodec is used */
0250:            private String formatName;
0251:
0252:            /** The specified <code>OperationRegistry</code> when TileCodec is used */
0253:            private transient OperationRegistry registry;
0254:
0255:            /**
0256:             * A table of counts of remote references to instances of this class
0257:             * (server only).
0258:             *
0259:             * <p> This table consists of entries with the keys being instances of
0260:             * <code>SerializableRenderedImage</code> and the values being
0261:             * <code>Integer</code>s the int value of which represents the number
0262:             * of remote <code>SerializableRenderedImage</code> objects which could
0263:             * potentially request a socket connection with the associated key. This
0264:             * table is necessary to prevent the garbage collector of the interpreter
0265:             * in which the server <code>SerializableRenderedImage</code> object is
0266:             * instantiated from finalizing the object - and thereby closing its
0267:             * server socket - when that object could still receive socket connection
0268:             * requests from its remote clients. The reference to the object in the
0269:             * static class variable ensures that the object will not be prematurely
0270:             * finalized.
0271:             */
0272:            private static transient Hashtable remoteReferenceCount;
0273:
0274:            /** Indicate that tilecodec is used in the transfering or not */
0275:            private boolean useTileCodec = false;
0276:
0277:            /** Cache the encoder factory */
0278:            private transient TileDecoderFactory tileDecoderFactory = null;
0279:
0280:            /** Cache the decoder factory */
0281:            private transient TileEncoderFactory tileEncoderFactory = null;
0282:
0283:            /** Cache the encoding/decoding parameters */
0284:            private TileCodecParameterList encodingParam = null;
0285:            private TileCodecParameterList decodingParam = null;
0286:
0287:            /**
0288:             * Increment the remote reference count of the argument.
0289:             *
0290:             * <p> If the argument is not already in the remote reference table,
0291:             * add it to the table with a count value of unity. If it exists in
0292:             * table, increment its count value.
0293:             *
0294:             * @parameter o The object the count value of which is to be incremented.
0295:             */
0296:            private static synchronized void incrementRemoteReferenceCount(
0297:                    Object o) {
0298:                if (remoteReferenceCount == null) {
0299:                    remoteReferenceCount = new Hashtable();
0300:                    remoteReferenceCount.put(o, new Integer(1));
0301:                } else {
0302:                    Integer count = (Integer) remoteReferenceCount.get(o);
0303:                    if (count == null) {
0304:                        remoteReferenceCount.put(o, new Integer(1));
0305:                    } else {
0306:                        remoteReferenceCount.put(o, new Integer(count
0307:                                .intValue() + 1));
0308:                    }
0309:                }
0310:            }
0311:
0312:            /**
0313:             * Decrement the remote reference count of the argument.
0314:             *
0315:             * <p> If the count value of the argument exists in the table its count
0316:             * value is decremented unless the count value is unity in which case the
0317:             * entry is removed from the table.
0318:             *
0319:             * @parameter o The object the count value of which is to be decremented.
0320:             */
0321:            private static synchronized void decrementRemoteReferenceCount(
0322:                    Object o) {
0323:                if (remoteReferenceCount != null) {
0324:                    Integer count = (Integer) remoteReferenceCount.get(o);
0325:                    if (count != null) {
0326:                        if (count.intValue() == 1) {
0327:                            remoteReferenceCount.remove(o);
0328:                        } else {
0329:                            remoteReferenceCount.put(o, new Integer(count
0330:                                    .intValue() - 1));
0331:                        }
0332:                    }
0333:                }
0334:            }
0335:
0336:            /**
0337:             * The default constructor.
0338:             */
0339:            SerializableRenderedImage() {
0340:            }
0341:
0342:            /**
0343:             * Constructs a <code>SerializableRenderedImage</code> wrapper for a
0344:             * <code>RenderedImage</code> source.  Image data may be serialized
0345:             * tile-by-tile or via a single deep copy.  Tile encoding and
0346:             * decoding may be effected via a <code>TileEncoder</code> and
0347:             * <code>TileDecoder</code> specified by format name.
0348:             *
0349:             * <p> It may be noted that if the <code>TileCodec</code> utilizes
0350:             * <code>Serializer</code>s for encoding the image data, and none
0351:             * is available for the <code>DataBuffer</code> of the supplied
0352:             * image, an error/exception may be encountered.
0353:             *
0354:             * @param source The <code>RenderedImage</code> source.
0355:             * @param useDeepCopy Whether a deep copy of the entire image Raster
0356:             *                    will be made during object serialization.
0357:             * @param registry The <code>OperationRegistry</code> to use in
0358:             *                 creating the <code>TileEncoder</code>.  The
0359:             *                 <code>TileDecoder</code> will of necessity be
0360:             *                 created using the default <code>OperationRegistry</code>
0361:             *                 as the specified <code>OperationRegistry</code> is not
0362:             *                 serialized.  If <code>null</code> the default registry
0363:             *                 will be used.
0364:             * @param formatName The name of the format used to encode the data.
0365:             *                   If <code>null</code> simple tile serialization will
0366:             *                   be performed either directly or by use of a "raw"
0367:             *                   <code>TileCodec</code>.
0368:             * @param encodingParam The parameters to be used for data encoding.  If
0369:             *                      <code>null</code> the default encoding
0370:             *                      <code>TileCodecParameterList</code> for this
0371:             *                      format will be used.  Ignored if
0372:             *                      <code>formatName</code> is <code>null</code>.
0373:             * @param decodingParam The parameters to be used for data decoding.  If
0374:             *                      <code>null</code> a complementary
0375:             *                      <code>TileCodecParameterList</code> will be
0376:             *                      derived from <code>encodingParam</code>.  Ignored
0377:             *                      if <code>formatName</code> is <code>null</code>.
0378:             *
0379:             * @exception IllegalArgumentException if <code>source</code>
0380:             *            is <code>null</code>.
0381:             * @exception IllegalArgumentException if no <code>Serializer</code>s
0382:             *            are available for the types of
0383:             *            <code>SampleModel</code>, and <code>ColorModel</code>
0384:             *            contained in the specified image.
0385:             */
0386:            public SerializableRenderedImage(RenderedImage source,
0387:                    boolean useDeepCopy, OperationRegistry registry,
0388:                    String formatName, TileCodecParameterList encodingParam,
0389:                    TileCodecParameterList decodingParam)
0390:                    throws NotSerializableException {
0391:                this (source, useDeepCopy, false);
0392:
0393:                // When the provided format name is null, return to directly serialize
0394:                // this image
0395:                if (formatName == null)
0396:                    return;
0397:
0398:                this .formatName = formatName;
0399:
0400:                // When the provided registry is null, use the default one
0401:                if (registry == null)
0402:                    registry = JAI.getDefaultInstance().getOperationRegistry();
0403:                this .registry = registry;
0404:
0405:                // Fix 4640094: When the provided encodingParam is null, use the default one
0406:                if (encodingParam == null) {
0407:                    TileCodecDescriptor tcd = getTileCodecDescriptor(
0408:                            "tileEncoder", formatName);
0409:                    encodingParam = tcd.getDefaultParameters("tileEncoder");
0410:                } else if (!formatName.equals(encodingParam.getFormatName())) {
0411:                    throw new IllegalArgumentException(JaiI18N
0412:                            .getString("UseTileCodec0"));
0413:                }
0414:
0415:                // Fix 4640094: When the provided decodingParam is null, use the default one
0416:                if (decodingParam == null) {
0417:                    TileCodecDescriptor tcd = getTileCodecDescriptor(
0418:                            "tileDecoder", formatName);
0419:                    decodingParam = tcd.getDefaultParameters("tileDecoder");
0420:                } else if (!formatName.equals(decodingParam.getFormatName())) {
0421:                    throw new IllegalArgumentException(JaiI18N
0422:                            .getString("UseTileCodec1"));
0423:                }
0424:
0425:                tileEncoderFactory = (TileEncoderFactory) registry.getFactory(
0426:                        "tileEncoder", formatName);
0427:                tileDecoderFactory = (TileDecoderFactory) registry.getFactory(
0428:                        "tileDecoder", formatName);
0429:                if (tileEncoderFactory == null || tileDecoderFactory == null)
0430:                    throw new RuntimeException(JaiI18N
0431:                            .getString("UseTileCodec2"));
0432:
0433:                this .encodingParam = encodingParam;
0434:                this .decodingParam = decodingParam;
0435:                useTileCodec = true;
0436:            }
0437:
0438:            /**
0439:             * Constructs a <code>SerializableRenderedImage</code> wrapper for a
0440:             * <code>RenderedImage</code> source.  Image data may be serialized
0441:             * tile-by-tile or via a single deep copy.  No <code>TileCodec</code>
0442:             * will be used, i.e., data will be transmitted using the serialization
0443:             * protocol for <code>Raster</code>s.
0444:             *
0445:             * @param source The <code>RenderedImage</code> source.
0446:             * @param useDeepCopy Whether a deep copy of the entire image Raster
0447:             * will be made during object serialization.
0448:             *
0449:             * @exception IllegalArgumentException if <code>source</code>
0450:             * is <code>null</code>.
0451:             * @exception IllegalArgumentException if no <code>Serializer</code>s
0452:             *            are available for the types of <code>DataBuffer</code>,
0453:             *            <code>SampleModel</code>, and <code>ColorModel</code>
0454:             *            contained in the specified image.
0455:             */
0456:            public SerializableRenderedImage(RenderedImage source,
0457:                    boolean useDeepCopy) {
0458:                this (source, useDeepCopy, true);
0459:            }
0460:
0461:            /**
0462:             * Constructs a <code>SerializableRenderedImage</code> wrapper for a
0463:             * <code>RenderedImage</code> source.  Image data will be serialized
0464:             * tile-by-tile if possible.  No <code>TileCodec</code>
0465:             * will be used, i.e., data will be transmitted using the serialization
0466:             * protocol for <code>Raster</code>s.
0467:             *
0468:             * @param source The <code>RenderedImage</code> source.
0469:             * @exception IllegalArgumentException if <code>source</code>
0470:             *            is <code>null</code>.
0471:             * @exception IllegalArgumentException if no <code>Serializer</code>s
0472:             *            are available for the types of <code>DataBuffer</code>,
0473:             *            <code>SampleModel</code>, and <code>ColorModel</code>
0474:             *            contained in the specified image.
0475:             */
0476:            public SerializableRenderedImage(RenderedImage source) {
0477:                this (source, false, true);
0478:            }
0479:
0480:            /**
0481:             * Constructs a <code>SerializableRenderedImage</code> wrapper for a
0482:             * <code>RenderedImage</code> source.
0483:             *
0484:             * @param source The <code>RenderedImage</code> source.
0485:             * @param useDeepCopy Whether a deep copy of the entire image Raster
0486:             * will be made during object serialization.
0487:             * @param checkDataBuffer Whether checking serializable for DataBuffer
0488:             * or not. If no <code>TileCodec</code> will be used, set it to true.
0489:             * If <code>TileCodec</code> will be used, it is set to false.
0490:             */
0491:
0492:            private SerializableRenderedImage(RenderedImage source,
0493:                    boolean useDeepCopy, boolean checkDataBuffer) {
0494:
0495:                UID = ImageUtil.generateID(this );
0496:
0497:                if (source == null) {
0498:                    throw new IllegalArgumentException(JaiI18N
0499:                            .getString("SerializableRenderedImage0"));
0500:                }
0501:
0502:                SampleModel sm = source.getSampleModel();
0503:                if (sm != null
0504:                        && SerializerFactory.getSerializer(sm.getClass()) == null) {
0505:                    throw new IllegalArgumentException(JaiI18N
0506:                            .getString("SerializableRenderedImage2"));
0507:                }
0508:
0509:                ColorModel cm = source.getColorModel();
0510:                if (cm != null
0511:                        && SerializerFactory.getSerializer(cm.getClass()) == null) {
0512:                    throw new IllegalArgumentException(JaiI18N
0513:                            .getString("SerializableRenderedImage3"));
0514:                }
0515:
0516:                if (checkDataBuffer) {
0517:                    Raster ras = source.getTile(source.getMinTileX(), source
0518:                            .getMinTileY());
0519:                    if (ras != null) {
0520:                        DataBuffer db = ras.getDataBuffer();
0521:                        if (db != null
0522:                                && SerializerFactory.getSerializer(db
0523:                                        .getClass()) == null)
0524:                            throw new IllegalArgumentException(JaiI18N
0525:                                    .getString("SerializableRenderedImage4"));
0526:                    }
0527:                }
0528:
0529:                // Set server flag.
0530:                isServer = true;
0531:
0532:                // Cache the deep copy flag.
0533:                this .useDeepCopy = useDeepCopy;
0534:
0535:                // Cache the parameter.
0536:                this .source = source;
0537:
0538:                // Set remote source flag.
0539:                this .isSourceRemote = source instanceof  RemoteImage;
0540:
0541:                // Initialize RenderedImage fields.
0542:                minX = source.getMinX();
0543:                minY = source.getMinY();
0544:                width = source.getWidth();
0545:                height = source.getHeight();
0546:                minTileX = source.getMinTileX();
0547:                minTileY = source.getMinTileY();
0548:                numXTiles = source.getNumXTiles();
0549:                numYTiles = source.getNumYTiles();
0550:                tileWidth = source.getTileWidth();
0551:                tileHeight = source.getTileHeight();
0552:                tileGridXOffset = source.getTileGridXOffset();
0553:                tileGridYOffset = source.getTileGridYOffset();
0554:                sampleModel = source.getSampleModel();
0555:                colorModel = source.getColorModel();
0556:                sources = new Vector();
0557:                sources.add(source);
0558:                properties = new Hashtable();
0559:                // XXX Property names should use CaselessStringKey for the
0560:                // keys so that case is preserved.
0561:                String[] propertyNames = source.getPropertyNames();
0562:                if (propertyNames != null) {
0563:                    for (int i = 0; i < propertyNames.length; i++) {
0564:                        properties.put(propertyNames[i], source
0565:                                .getProperty(propertyNames[i]));
0566:                    }
0567:                }
0568:
0569:                // Initialize the image bounds.
0570:                imageBounds = new Rectangle(minX, minY, width, height);
0571:
0572:                // Initialize the host field.
0573:                try {
0574:                    host = InetAddress.getLocalHost();
0575:                } catch (UnknownHostException e) {
0576:                    throw new RuntimeException(e.getMessage());
0577:                }
0578:
0579:                // Unset the server availability flag.
0580:                serverOpen = false;
0581:            }
0582:
0583:            /**
0584:             * Private implementation of tile server.
0585:             */
0586:            private class TileServer implements  Runnable {
0587:                /**
0588:                 * Provide Rasters to clients on request.
0589:                 *
0590:                 * <p> This method is called by the data server thread when a deep copy
0591:                 * of the source image Raster is not being used. A socket connection is
0592:                 * set up at a well known address to which clients may connect. After a
0593:                 * client connects it transmits a Rectangle object which is read by
0594:                 * this method. The Raster corresponding to this Rectangle is then
0595:                 * retrieved from the source image and transmitted back over the
0596:                 * socket connection.
0597:                 *
0598:                 * <p> The server loop will continue until this object is garbage
0599:                 * collected.
0600:                 */
0601:                public void run() {
0602:                    // Loop while the server availability flag is set.
0603:                    while (serverOpen) {
0604:                        // Wait for a client connection request.
0605:                        Socket socket = null;
0606:                        try {
0607:                            socket = serverSocket.accept();
0608:                            socket.setSoLinger(true, 1);
0609:                        } catch (InterruptedIOException e) {
0610:                            // accept() timeout: restart loop to check
0611:                            // availability flag.
0612:                            continue;
0613:                        } catch (SocketException e) {
0614:                            sendExceptionToListener(
0615:                                    JaiI18N
0616:                                            .getString("SerializableRenderedImage5"),
0617:                                    new ImagingException(
0618:                                            JaiI18N
0619:                                                    .getString("SerializableRenderedImage5"),
0620:                                            e));
0621:                            //                    throw new RuntimeException(e.getMessage());
0622:                        } catch (IOException e) {
0623:                            sendExceptionToListener(
0624:                                    JaiI18N
0625:                                            .getString("SerializableRenderedImage6"),
0626:                                    new ImagingException(
0627:                                            JaiI18N
0628:                                                    .getString("SerializableRenderedImage6"),
0629:                                            e));
0630:                        }
0631:
0632:                        // Get the socket input and output streams and wrap object
0633:                        // input and output streams around them, respectively.
0634:                        InputStream in = null;
0635:                        OutputStream out = null;
0636:                        ObjectInputStream objectIn = null;
0637:                        ObjectOutputStream objectOut = null;
0638:                        try {
0639:                            in = socket.getInputStream();
0640:                            out = socket.getOutputStream();
0641:                            objectIn = new ObjectInputStream(in);
0642:                            objectOut = new ObjectOutputStream(out);
0643:                        } catch (IOException e) {
0644:                            sendExceptionToListener(
0645:                                    JaiI18N
0646:                                            .getString("SerializableRenderedImage7"),
0647:                                    new ImagingException(
0648:                                            JaiI18N
0649:                                                    .getString("SerializableRenderedImage7"),
0650:                                            e));
0651:                            //                    throw new RuntimeException(e.getMessage());
0652:                        }
0653:
0654:                        // Read the Object from the object stream.
0655:                        Object obj = null;
0656:                        try {
0657:                            obj = objectIn.readObject();
0658:                        } catch (IOException e) {
0659:                            sendExceptionToListener(
0660:                                    JaiI18N
0661:                                            .getString("SerializableRenderedImage8"),
0662:                                    new ImagingException(
0663:                                            JaiI18N
0664:                                                    .getString("SerializableRenderedImage8"),
0665:                                            e));
0666:                            //                    throw new RuntimeException(e.getMessage());
0667:                        } catch (ClassNotFoundException e) {
0668:                            sendExceptionToListener(
0669:                                    JaiI18N
0670:                                            .getString("SerializableRenderedImage9"),
0671:                                    new ImagingException(
0672:                                            JaiI18N
0673:                                                    .getString("SerializableRenderedImage9"),
0674:                                            e));
0675:                        }
0676:
0677:                        // Switch according to object class; ignore unsupported types.
0678:                        if (obj instanceof  String
0679:                                && ((String) obj).equals(CLOSE_MESSAGE)) {
0680:
0681:                            try {
0682:                                objectOut.writeObject(CLOSE_ACK);
0683:                            } catch (IOException e) {
0684:                                sendExceptionToListener(
0685:                                        JaiI18N
0686:                                                .getString("SerializableRenderedImage17"),
0687:                                        new ImagingException(
0688:                                                JaiI18N
0689:                                                        .getString("SerializableRenderedImage17"),
0690:                                                e));
0691:                                // throw new RuntimeException(e.getMessage());
0692:                            }
0693:
0694:                            // Decrement the remote reference count.
0695:                            decrementRemoteReferenceCount(this );
0696:                        } else if (obj instanceof  Rectangle) {
0697:
0698:                            // Retrieve the Raster of data from the source image.
0699:                            Raster raster = source.getData((Rectangle) obj);
0700:                            // Write the serializable Raster to the
0701:                            // object output stream.
0702:
0703:                            if (useTileCodec) {
0704:                                byte[] buf = encodeRasterToByteArray(raster);
0705:                                try {
0706:                                    objectOut.writeObject(buf);
0707:                                } catch (IOException e) {
0708:                                    sendExceptionToListener(
0709:                                            JaiI18N
0710:                                                    .getString("SerializableRenderedImage10"),
0711:                                            new ImagingException(
0712:                                                    JaiI18N
0713:                                                            .getString("SerializableRenderedImage10"),
0714:                                                    e));
0715:                                    //                            throw new RuntimeException(e.getMessage());
0716:                                }
0717:                            } else {
0718:                                try {
0719:                                    objectOut.writeObject(SerializerFactory
0720:                                            .getState(raster, null));
0721:                                } catch (IOException e) {
0722:                                    sendExceptionToListener(
0723:                                            JaiI18N
0724:                                                    .getString("SerializableRenderedImage10"),
0725:                                            new ImagingException(
0726:                                                    JaiI18N
0727:                                                            .getString("SerializableRenderedImage10"),
0728:                                                    e));
0729:                                    //                            throw new RuntimeException(e.getMessage());
0730:                                }
0731:                            }
0732:                        }
0733:
0734:                        // XXX Concerning serialization of properties, perhaps the
0735:                        // best approach would be to serialize all the properties up
0736:                        // front if a deep copy were being made but otherwise to wait
0737:                        // until the first property request was received before
0738:                        // transmitting any property values. When the first request
0739:                        // was made, all property values would be transmitted and then
0740:                        // cached. Up front serialization might in both cases include
0741:                        // transmitting all names. If property serialization were
0742:                        // deferred, then a new message branch would be added here
0743:                        // to retrieve the properties which could be obtained as
0744:                        // a PropertySourceImpl. If properties are also served up
0745:                        // then this inner class should be renamed "DataServer".
0746:
0747:                        // Close the various streams and the socket itself.
0748:                        try {
0749:                            objectOut.flush();
0750:                            socket.shutdownOutput();
0751:                            socket.shutdownInput();
0752:                            objectOut.close();
0753:                            objectIn.close();
0754:                            out.close();
0755:                            in.close();
0756:                            socket.close();
0757:                        } catch (IOException e) {
0758:                            sendExceptionToListener(
0759:                                    JaiI18N
0760:                                            .getString("SerializableRenderedImage10"),
0761:                                    new ImagingException(
0762:                                            JaiI18N
0763:                                                    .getString("SerializableRenderedImage10"),
0764:                                            e));
0765:                            //                    throw new RuntimeException(e.getMessage());
0766:                        }
0767:                    }
0768:                }
0769:            }
0770:
0771:            // --- Begin implementation of java.awt.image.RenderedImage. ---
0772:
0773:            public WritableRaster copyData(WritableRaster dest) {
0774:                if (isServer || isSourceRemote) {
0775:                    return source.copyData(dest);
0776:                }
0777:
0778:                Rectangle region;
0779:                if (dest == null) {
0780:                    region = imageBounds;
0781:                    SampleModel destSM = getSampleModel()
0782:                            .createCompatibleSampleModel(region.width,
0783:                                    region.height);
0784:                    dest = Raster.createWritableRaster(destSM, new Point(
0785:                            region.x, region.y));
0786:                } else {
0787:                    region = dest.getBounds().intersection(imageBounds);
0788:                }
0789:
0790:                if (!region.isEmpty()) {
0791:                    int startTileX = PlanarImage.XToTileX(region.x,
0792:                            tileGridXOffset, tileWidth);
0793:                    int startTileY = PlanarImage.YToTileY(region.y,
0794:                            tileGridYOffset, tileHeight);
0795:                    int endTileX = PlanarImage.XToTileX(region.x + region.width
0796:                            - 1, tileGridXOffset, tileWidth);
0797:                    int endTileY = PlanarImage.YToTileY(region.y
0798:                            + region.height - 1, tileGridYOffset, tileHeight);
0799:
0800:                    SampleModel[] sampleModels = { getSampleModel() };
0801:                    int tagID = RasterAccessor.findCompatibleTag(sampleModels,
0802:                            dest.getSampleModel());
0803:
0804:                    RasterFormatTag srcTag = new RasterFormatTag(
0805:                            getSampleModel(), tagID);
0806:                    RasterFormatTag dstTag = new RasterFormatTag(dest
0807:                            .getSampleModel(), tagID);
0808:
0809:                    for (int ty = startTileY; ty <= endTileY; ty++) {
0810:                        for (int tx = startTileX; tx <= endTileX; tx++) {
0811:                            Raster tile = getTile(tx, ty);
0812:                            Rectangle subRegion = region.intersection(tile
0813:                                    .getBounds());
0814:
0815:                            RasterAccessor s = new RasterAccessor(tile,
0816:                                    subRegion, srcTag, getColorModel());
0817:                            RasterAccessor d = new RasterAccessor(dest,
0818:                                    subRegion, dstTag, null);
0819:                            ImageUtil.copyRaster(s, d);
0820:                        }
0821:                    }
0822:                }
0823:
0824:                return dest;
0825:            }
0826:
0827:            public ColorModel getColorModel() {
0828:                return colorModel;
0829:            }
0830:
0831:            public Raster getData() {
0832:                if (isServer || isSourceRemote) {
0833:                    return source.getData();
0834:                }
0835:
0836:                return getData(imageBounds);
0837:            }
0838:
0839:            public Raster getData(Rectangle rect) {
0840:                Raster raster = null;
0841:
0842:                // Branch according to whether the object is a data server or, if not,
0843:                // according to whether it is a data client and using a deep copy of
0844:                // the source data or pulling the data as needed over a socket.
0845:                if (isServer || isSourceRemote) {
0846:                    raster = source.getData(rect);
0847:                } else if (useDeepCopy) {
0848:                    raster = imageRaster.createChild(rect.x, rect.y,
0849:                            rect.width, rect.height, rect.x, rect.y, null);
0850:                } else {
0851:                    // TODO: Use a Hashtable to store Rasters as they are pulled over
0852:                    // the network and look them up here using "rect" as key?
0853:
0854:                    // Connect to the data server.
0855:                    Socket socket = connectToServer();
0856:
0857:                    // Get the socket input and output streams and wrap object
0858:                    // input and output streams around them, respectively.
0859:                    OutputStream out = null;
0860:                    ObjectOutputStream objectOut = null;
0861:                    InputStream in = null;
0862:                    ObjectInputStream objectIn = null;
0863:                    try {
0864:                        out = socket.getOutputStream();
0865:                        objectOut = new ObjectOutputStream(out);
0866:                        in = socket.getInputStream();
0867:                        objectIn = new ObjectInputStream(in);
0868:                    } catch (IOException e) {
0869:                        sendExceptionToListener(
0870:                                JaiI18N.getString("SerializableRenderedImage7"),
0871:                                new ImagingException(
0872:                                        JaiI18N
0873:                                                .getString("SerializableRenderedImage7"),
0874:                                        e));
0875:                        //                throw new RuntimeException(e.getMessage());
0876:                    }
0877:
0878:                    // Write the Rectangle to the object output stream.
0879:                    try {
0880:                        objectOut.writeObject(rect);
0881:                    } catch (IOException e) {
0882:                        sendExceptionToListener(
0883:                                JaiI18N
0884:                                        .getString("SerializableRenderedImage10"),
0885:                                new ImagingException(
0886:                                        JaiI18N
0887:                                                .getString("SerializableRenderedImage10"),
0888:                                        e));
0889:                        //                throw new RuntimeException(e.getMessage());
0890:                    }
0891:
0892:                    // Read serialized form of the Raster from object output stream.
0893:                    Object object = null;
0894:                    try {
0895:                        object = objectIn.readObject();
0896:                    } catch (IOException e) {
0897:                        sendExceptionToListener(
0898:                                JaiI18N.getString("SerializableRenderedImage8"),
0899:                                new ImagingException(
0900:                                        JaiI18N
0901:                                                .getString("SerializableRenderedImage8"),
0902:                                        e));
0903:                        //                throw new RuntimeException(e.getMessage());
0904:                    } catch (ClassNotFoundException e) {
0905:                        sendExceptionToListener(
0906:                                JaiI18N.getString("SerializableRenderedImage9"),
0907:                                new ImagingException(
0908:                                        JaiI18N
0909:                                                .getString("SerializableRenderedImage9"),
0910:                                        e));
0911:                    }
0912:
0913:                    if (useTileCodec) {
0914:                        byte[] buf = (byte[]) object;
0915:                        raster = decodeRasterFromByteArray(buf);
0916:                    } else {
0917:                        if (!(object instanceof  SerializableState))
0918:                            raster = null;
0919:                        // Reconstruct the Raster from the serialized form.
0920:                        SerializableState ss = (SerializableState) object;
0921:                        Class c = ss.getObjectClass();
0922:                        if (Raster.class.isAssignableFrom(c)) {
0923:                            raster = (Raster) ss.getObject();
0924:                        } else
0925:                            raster = null;
0926:                    }
0927:
0928:                    // Close the various streams and the socket.
0929:                    try {
0930:                        objectOut.flush();
0931:                        socket.shutdownOutput();
0932:                        socket.shutdownInput();
0933:                        objectOut.close();
0934:                        out.close();
0935:                        objectIn.close();
0936:                        in.close();
0937:                        socket.close();
0938:                    } catch (IOException e) {
0939:                        String message = JaiI18N
0940:                                .getString("SerializableRenderedImage11");
0941:                        sendExceptionToListener(message, new ImagingException(
0942:                                message, e));
0943:                        //                throw new RuntimeException(e.getMessage());
0944:                    }
0945:
0946:                    // If the rectangle equals the image bounds, cache the Raster,
0947:                    // switch to "deep copy" mode, and notify the data server.
0948:                    if (imageBounds.equals(rect)) {
0949:
0950:                        closeClient();
0951:
0952:                        imageRaster = raster;
0953:                        useDeepCopy = true;
0954:                    }
0955:                }
0956:
0957:                return raster;
0958:            }
0959:
0960:            public int getHeight() {
0961:                return height;
0962:            }
0963:
0964:            public int getMinTileX() {
0965:                return minTileX;
0966:            }
0967:
0968:            public int getMinTileY() {
0969:                return minTileY;
0970:            }
0971:
0972:            public int getMinX() {
0973:                return minX;
0974:            }
0975:
0976:            public int getMinY() {
0977:                return minY;
0978:            }
0979:
0980:            public int getNumXTiles() {
0981:                return numXTiles;
0982:            }
0983:
0984:            public int getNumYTiles() {
0985:                return numYTiles;
0986:            }
0987:
0988:            // XXX Should getProperty() request property values over a socket
0989:            // connection also?
0990:            public Object getProperty(String name) {
0991:                // XXX Use CaselessStringKeys for the property name.
0992:                Object property = properties.get(name);
0993:                return property == null ? Image.UndefinedProperty : property;
0994:            }
0995:
0996:            public String[] getPropertyNames() {
0997:                String[] names = null;
0998:                if (!properties.isEmpty()) {
0999:                    names = new String[properties.size()];
1000:                    Enumeration keys = properties.keys();
1001:                    int index = 0;
1002:                    while (keys.hasMoreElements()) {
1003:                        // XXX If CaselessStringKey keys are used then
1004:                        // getName() would have to be called here to get the
1005:                        // prop name from the key.
1006:                        names[index++] = (String) keys.nextElement();
1007:                    }
1008:                }
1009:                return names;
1010:            }
1011:
1012:            public SampleModel getSampleModel() {
1013:                return sampleModel;
1014:            }
1015:
1016:            /**
1017:             * If this <code>SerializableRenderedImage</code> has not been
1018:             * serialized, this method returns a <code>Vector</code> containing
1019:             * only the <code>RenderedImage</code> passed to the constructor; if
1020:             * this image has been deserialized, it returns <code>null</code>.
1021:             */
1022:            public Vector getSources() {
1023:                return sources;
1024:            }
1025:
1026:            public Raster getTile(int tileX, int tileY) {
1027:                if (isServer || isSourceRemote) {
1028:                    return source.getTile(tileX, tileY);
1029:                }
1030:
1031:                TileCache cache = JAI.getDefaultInstance().getTileCache();
1032:                if (cache != null) {
1033:                    Raster tile = cache.getTile(this , tileX, tileY);
1034:                    if (tile != null)
1035:                        return tile;
1036:                }
1037:
1038:                // Determine the active area; tile intersects with image's bounds.
1039:                Rectangle imageBounds = new Rectangle(getMinX(), getMinY(),
1040:                        getWidth(), getHeight());
1041:                Rectangle destRect = imageBounds.intersection(new Rectangle(
1042:                        tileXToX(tileX), tileYToY(tileY), getTileWidth(),
1043:                        getTileHeight()));
1044:
1045:                Raster tile = getData(destRect);
1046:
1047:                if (cache != null) {
1048:                    cache.add(this , tileX, tileY, tile);
1049:                }
1050:
1051:                return tile;
1052:            }
1053:
1054:            /**
1055:             * Returns a unique identifier (UID) for this <code>RenderedImage</code>.
1056:             * This UID may be used when the potential redundancy of the value
1057:             * returned by the <code>hashCode()</code> method is unacceptable.
1058:             * An example of this is in generating a key for storing image tiles
1059:             * in a cache.
1060:             */
1061:            public Object getImageID() {
1062:                return UID;
1063:            }
1064:
1065:            /**
1066:             * Converts a horizontal tile index into the X coordinate of its
1067:             * upper left pixel.  No attempt is made to detect out-of-range
1068:             * indices.
1069:             *
1070:             * <p> This method is implemented in terms of the <code>PlanarImage</code>
1071:             * static method <code>tileXToX()</code> applied to the values returned
1072:             * by primitive layout accessors.
1073:             *
1074:             * @param tx the horizontal index of a tile.
1075:             * @return the X coordinate of the tile's upper left pixel.
1076:             */
1077:            private int tileXToX(int tx) {
1078:                return PlanarImage.tileXToX(tx, getTileGridXOffset(),
1079:                        getTileWidth());
1080:            }
1081:
1082:            /**
1083:             * Converts a vertical tile index into the Y coordinate of its
1084:             * upper left pixel.  No attempt is made to detect out-of-range
1085:             * indices.
1086:             *
1087:             * <p> This method is implemented in terms of the
1088:             * <code>PlanarImage</code> static method <code>tileYToY()</code>
1089:             * applied to the values returned by primitive layout accessors.
1090:             *
1091:             * @param ty the vertical index of a tile.
1092:             * @return the Y coordinate of the tile's upper left pixel.
1093:             */
1094:            private int tileYToY(int ty) {
1095:                return PlanarImage.tileYToY(ty, getTileGridYOffset(),
1096:                        getTileHeight());
1097:            }
1098:
1099:            public int getTileGridXOffset() {
1100:                return tileGridXOffset;
1101:            }
1102:
1103:            public int getTileGridYOffset() {
1104:                return tileGridYOffset;
1105:            }
1106:
1107:            public int getTileHeight() {
1108:                return tileHeight;
1109:            }
1110:
1111:            public int getTileWidth() {
1112:                return tileWidth;
1113:            }
1114:
1115:            public int getWidth() {
1116:                return width;
1117:            }
1118:
1119:            // --- End implementation of java.awt.image.RenderedImage. ---
1120:
1121:            /**
1122:             * Create a server socket and start the server in a separate thread.
1123:             *
1124:             * <p> Note that this method should be called only the first time this
1125:             * object is serialized and only if a deep copy is not being used. If
1126:             * a deep copy is used there is no need to serve clients data on demand.
1127:             * However if data service is being provided, there is no need to create
1128:             * multiple threads for the single object as a single server thread
1129:             * should be able to service multiple remote objects.
1130:             */
1131:            private synchronized void openServer() throws IOException,
1132:                    SocketException {
1133:                if (!serverOpen) {
1134:                    // Create a ServerSocket.
1135:                    serverSocket = new ServerSocket(0);
1136:
1137:                    // Set the ServerSocket accept() method timeout period.
1138:                    serverSocket.setSoTimeout(SERVER_TIMEOUT);
1139:
1140:                    // Initialize the port field.
1141:                    port = serverSocket.getLocalPort();
1142:
1143:                    // Set the server availability flag.
1144:                    serverOpen = true;
1145:
1146:                    // Spawn a child thread and return the parent thread to the caller.
1147:                    serverThread = new Thread(new TileServer());
1148:                    serverThread.setDaemon(true);
1149:                    serverThread.start();
1150:
1151:                    // Increment the remote reference count.
1152:                    incrementRemoteReferenceCount(this );
1153:                }
1154:            }
1155:
1156:            /**
1157:             * Transmit a message to the data server to indicate that the client
1158:             * will no longer request socket connections.
1159:             */
1160:            private void closeClient() {
1161:
1162:                // Connect to the data server.
1163:                Socket socket = connectToServer();
1164:
1165:                // Get the socket output stream and wrap an object
1166:                // output stream around it.
1167:                OutputStream out = null;
1168:                ObjectOutputStream objectOut = null;
1169:                ObjectInputStream objectIn = null;
1170:                try {
1171:                    out = socket.getOutputStream();
1172:                    objectOut = new ObjectOutputStream(out);
1173:                    objectIn = new ObjectInputStream(socket.getInputStream());
1174:                } catch (IOException e) {
1175:                    sendExceptionToListener(
1176:                            JaiI18N.getString("SerializableRenderedImage7"),
1177:                            new ImagingException(JaiI18N
1178:                                    .getString("SerializableRenderedImage7"), e));
1179:                    //            throw new RuntimeException(e.getMessage());
1180:                }
1181:
1182:                // Write CLOSE_MESSAGE to the object output stream.
1183:                try {
1184:                    objectOut.writeObject(CLOSE_MESSAGE);
1185:                } catch (IOException e) {
1186:                    sendExceptionToListener(JaiI18N
1187:                            .getString("SerializableRenderedImage13"),
1188:                            new ImagingException(JaiI18N
1189:                                    .getString("SerializableRenderedImage13"),
1190:                                    e));
1191:                    //            throw new RuntimeException(e.getMessage());
1192:                }
1193:
1194:                try {
1195:                    objectIn.readObject();
1196:                } catch (IOException e) {
1197:                    sendExceptionToListener(
1198:                            JaiI18N.getString("SerializableRenderedImage8"),
1199:                            new ImagingException(JaiI18N
1200:                                    .getString("SerializableRenderedImage8"), e));
1201:                } catch (ClassNotFoundException cnfe) {
1202:                    sendExceptionToListener(JaiI18N
1203:                            .getString("SerializableRenderedImage9"),
1204:                            new ImagingException(JaiI18N
1205:                                    .getString("SerializableRenderedImage9"),
1206:                                    cnfe));
1207:                }
1208:
1209:                // Close the streams and the socket.
1210:                try {
1211:                    objectOut.flush();
1212:                    socket.shutdownOutput();
1213:                    objectOut.close();
1214:                    out.close();
1215:                    objectIn.close();
1216:                    socket.close();
1217:                } catch (IOException e) {
1218:                    sendExceptionToListener(JaiI18N
1219:                            .getString("SerializableRenderedImage11"),
1220:                            new ImagingException(JaiI18N
1221:                                    .getString("SerializableRenderedImage11"),
1222:                                    e));
1223:                    //            throw new RuntimeException(e.getMessage());
1224:                }
1225:            }
1226:
1227:            /**
1228:             * Obtain a connection to the data server socket. This is used only if a
1229:             * deep copy of the image Raster has not been made.
1230:             */
1231:            private Socket connectToServer() {
1232:                // Open a connection to the data server.
1233:                Socket socket = null;
1234:                try {
1235:                    socket = new Socket(host, port);
1236:                    socket.setSoLinger(true, 1);
1237:                } catch (IOException e) {
1238:                    sendExceptionToListener(JaiI18N
1239:                            .getString("SerializableRenderedImage14"),
1240:                            new ImagingException(JaiI18N
1241:                                    .getString("SerializableRenderedImage14"),
1242:                                    e));
1243:                    //            throw new RuntimeException(e.getMessage());
1244:                }
1245:
1246:                return socket;
1247:            }
1248:
1249:            /**
1250:             * When useTileCodec is set, encode the provided raster into
1251:             * a byte array.
1252:             */
1253:            private byte[] encodeRasterToByteArray(Raster raster) {
1254:                ByteArrayOutputStream bos = new ByteArrayOutputStream();
1255:                TileEncoder encoder = tileEncoderFactory.createEncoder(bos,
1256:                        encodingParam, raster.getSampleModel());
1257:                try {
1258:                    encoder.encode(raster);
1259:                    return bos.toByteArray();
1260:                } catch (IOException e) {
1261:                    sendExceptionToListener(JaiI18N
1262:                            .getString("SerializableRenderedImage15"),
1263:                            new ImagingException(JaiI18N
1264:                                    .getString("SerializableRenderedImage15"),
1265:                                    e));
1266:                    //            throw new RuntimeException(e.getMessage());
1267:                }
1268:                return null;
1269:            }
1270:
1271:            /**
1272:             * When useTileCodec is set, decode the raster from a byte array.
1273:             */
1274:            private Raster decodeRasterFromByteArray(byte[] buf) {
1275:                ByteArrayInputStream bis = new ByteArrayInputStream(buf);
1276:
1277:                // Fix 4640094 Tilecodec doesn't work well in SerializableRenderedImage
1278:                // Currently, ParameterListDescriptor is singleton to a specific
1279:                // tile codec and mode.  After deserialization this property is gone.
1280:                // So need to copy the parameter values into the newly created object
1281:                if (tileDecoderFactory == null) {
1282:                    // Use the default operation registry as described in the spec
1283:                    // of the constructor.
1284:                    if (registry == null)
1285:                        registry = JAI.getDefaultInstance()
1286:                                .getOperationRegistry();
1287:                    tileDecoderFactory = (TileDecoderFactory) registry
1288:                            .getFactory("tileDecoder", formatName);
1289:
1290:                    TileCodecParameterList temp = decodingParam;
1291:
1292:                    if (temp != null) {
1293:                        TileCodecDescriptor tcd = getTileCodecDescriptor(
1294:                                "tileDecoder", formatName);
1295:                        ParameterListDescriptor pld = tcd
1296:                                .getParameterListDescriptor("tileDecoder");
1297:                        decodingParam = new TileCodecParameterList(formatName,
1298:                                new String[] { "tileDecoder" }, pld);
1299:                        String[] names = pld.getParamNames();
1300:
1301:                        if (names != null)
1302:                            for (int i = 0; i < names.length; i++)
1303:                                decodingParam.setParameter(names[i], temp
1304:                                        .getObjectParameter(names[i]));
1305:
1306:                    } else
1307:                        decodingParam = getTileCodecDescriptor("tileDecoder",
1308:                                formatName).getDefaultParameters("tileDecoder");
1309:                }
1310:
1311:                TileDecoder decoder = tileDecoderFactory.createDecoder(bis,
1312:                        decodingParam);
1313:                try {
1314:                    return decoder.decode();
1315:                } catch (IOException e) {
1316:                    sendExceptionToListener(JaiI18N
1317:                            .getString("SerializableRenderedImage16"),
1318:                            new ImagingException(JaiI18N
1319:                                    .getString("SerializableRenderedImage16"),
1320:                                    e));
1321:                    //            throw new RuntimeException(e.getMessage());
1322:                }
1323:                return null;
1324:            }
1325:
1326:            /**
1327:             * If a deep copy is not being used, unset the data server availability
1328:             * flag and wait for the server thread to rejoin the current thread.
1329:             */
1330:            protected void finalize() throws Throwable {
1331:                dispose();
1332:
1333:                // Forward to the parent class.
1334:                super .finalize();
1335:            }
1336:
1337:            /**
1338:             * Provides a hint that an image will no longer be accessed from a
1339:             * reference in user space.  The results are equivalent to those
1340:             * that occur when the program loses its last reference to this
1341:             * image, the garbage collector discovers this, and finalize is
1342:             * called.  This can be used as a hint in situations where waiting
1343:             * for garbage collection would be overly conservative, e.g., there
1344:             * are a large number of socket connections which may be opened to
1345:             * transmit tile data.
1346:             *
1347:             * <p> <code>SerializableRenderedImage</code> defines this method to
1348:             * behave as follows:
1349:             * <ul>
1350:             * <li>if the image is acting as a server, i.e., has never been
1351:             * serialized and may be providing data to serialized
1352:             * versions of itself, it makes itself unavailable to further
1353:             * client requests and closes its socket;</li>
1354:             * <li>if the image is acting as a client, i.e., has been serialized
1355:             * and may be requesting data from a remote, pre-serialization version
1356:             * of itself, it sends a message to its remote self indicating that it
1357:             * will no longer be making requests.</li>
1358:             * </ul>
1359:             *
1360:             * <p> The results of referencing an image after a call to
1361:             * <code>dispose()</code> are undefined.
1362:             */
1363:            public void dispose() {
1364:                // Rejoin the server thread if using a socket-based server.
1365:                if (isServer) {
1366:                    if (serverOpen) {
1367:                        // Unset availability flag so server loop exits.
1368:                        serverOpen = false;
1369:
1370:                        // Wait for the server (child) thread to die.
1371:                        try {
1372:                            serverThread.join(2 * SERVER_TIMEOUT);
1373:                        } catch (Exception e) {
1374:                            // Ignore the Exception.
1375:                        }
1376:
1377:                        // Close the server socket.
1378:                        try {
1379:                            serverSocket.close();
1380:                        } catch (Exception e) {
1381:                            // Ignore the Exception.
1382:                        }
1383:                    }
1384:                } else { // client
1385:                    // Transmit a message to the server to indicate the child's exit.
1386:                    closeClient();
1387:                }
1388:            }
1389:
1390:            /**
1391:             * Custom serialization method. In addition to all non-transient fields,
1392:             * the SampleModel, source vector, and properties table are serialized.
1393:             * If a deep copy of the source image Raster is being used this is also
1394:             * serialized.
1395:             */
1396:            private void writeObject(ObjectOutputStream out) throws IOException {
1397:                if (!useDeepCopy) {
1398:                    // Start the data server.
1399:                    try {
1400:                        openServer();
1401:                    } catch (Exception e1) {
1402:                        if (e1 instanceof  SocketException) { // setSoTimeout() failed.
1403:                            if (serverSocket != null) { // XXX Facultative
1404:                                try {
1405:                                    serverSocket.close();
1406:                                } catch (IOException e2) {
1407:                                    // Ignore the exception.
1408:                                }
1409:                            }
1410:                        }
1411:
1412:                        // Since server socket creation failed, use a deep copy.
1413:                        serverOpen = false; // XXX Facultative
1414:                        useDeepCopy = true;
1415:                    }
1416:                }
1417:
1418:                // Write non-static and non-transient fields.
1419:                out.defaultWriteObject();
1420:
1421:                // Write RMI properties of RemoteImage.
1422:                if (isSourceRemote) {
1423:                    String remoteClass = source.getClass().getName();
1424:                    out.writeObject(source.getProperty(remoteClass
1425:                            + ".serverName"));
1426:                    out.writeObject(source.getProperty(remoteClass + ".id"));
1427:                }
1428:
1429:                // Remove non-serializable elements from table of properties.
1430:                Hashtable propertyTable = properties;
1431:                boolean propertiesCloned = false;
1432:                Enumeration keys = propertyTable.keys();
1433:                while (keys.hasMoreElements()) {
1434:                    Object key = keys.nextElement();
1435:                    if (!(properties.get(key) instanceof  Serializable)) {
1436:                        if (!propertiesCloned) {
1437:                            propertyTable = (Hashtable) properties.clone();
1438:                            propertiesCloned = true;
1439:                        }
1440:                        propertyTable.remove(key);
1441:                    }
1442:                }
1443:
1444:                // Write the source vector and properties table.
1445:                out.writeObject(SerializerFactory.getState(sampleModel, null));
1446:                out.writeObject(SerializerFactory.getState(colorModel, null));
1447:                out.writeObject(propertyTable);
1448:
1449:                // Make a deep copy of the image raster.
1450:                if (useDeepCopy) {
1451:                    if (useTileCodec)
1452:                        out.writeObject(encodeRasterToByteArray(source
1453:                                .getData()));
1454:                    else {
1455:                        out.writeObject(SerializerFactory.getState(source
1456:                                .getData(), null));
1457:                    }
1458:                }
1459:            }
1460:
1461:            /**
1462:             * Custom deserialization method. In addition to all non-transient fields,
1463:             * the SampleModel, source vector, and properties table are deserialized.
1464:             * If a deep copy of the source image Raster is being used this is also
1465:             * deserialized.
1466:             */
1467:            private void readObject(ObjectInputStream in) throws IOException,
1468:                    ClassNotFoundException {
1469:                isServer = false;
1470:                source = null;
1471:                serverOpen = false;
1472:                serverSocket = null;
1473:                serverThread = null;
1474:                colorModel = null;
1475:
1476:                // Read non-static and non-transient fields.
1477:                in.defaultReadObject();
1478:
1479:                if (isSourceRemote) {
1480:                    // Read RMI properties of RemoteImage.
1481:                    String serverName = (String) in.readObject();
1482:                    Long id = (Long) in.readObject();
1483:
1484:                    // Recreate remote source using the ID directly.
1485:                    source = new RemoteImage(
1486:                            serverName + "::" + id.longValue(),
1487:                            (RenderedImage) null);
1488:                }
1489:
1490:                // Read the source vector and properties table.
1491:                SerializableState smState = (SerializableState) in.readObject();
1492:                sampleModel = (SampleModel) smState.getObject();
1493:                SerializableState cmState = (SerializableState) in.readObject();
1494:                colorModel = (ColorModel) cmState.getObject();
1495:                properties = (Hashtable) in.readObject();
1496:
1497:                // Read the image Raster.
1498:                if (useDeepCopy) {
1499:                    if (useTileCodec)
1500:                        imageRaster = decodeRasterFromByteArray((byte[]) in
1501:                                .readObject());
1502:                    else {
1503:                        SerializableState rasState = (SerializableState) in
1504:                                .readObject();
1505:                        imageRaster = (Raster) rasState.getObject();
1506:                    }
1507:                }
1508:            }
1509:
1510:            private TileCodecDescriptor getTileCodecDescriptor(
1511:                    String registryMode, String formatName) {
1512:                if (registry == null)
1513:                    return (TileCodecDescriptor) JAI.getDefaultInstance()
1514:                            .getOperationRegistry().getDescriptor(registryMode,
1515:                                    formatName);
1516:                return (TileCodecDescriptor) registry.getDescriptor(
1517:                        registryMode, formatName);
1518:            }
1519:
1520:            void sendExceptionToListener(String message, Exception e) {
1521:                ImagingListener listener = JAI.getDefaultInstance()
1522:                        .getImagingListener();
1523:                listener.errorOccurred(message, e, this , false);
1524:            }
1525:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.