0001: /*
0002: * $RCSfile: JAIRMIImageServer.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:56:51 $
0010: * $State: Exp $
0011: */package com.sun.media.jai.rmi;
0012:
0013: import java.awt.Dimension;
0014: import java.awt.Rectangle;
0015: import java.awt.RenderingHints;
0016: import java.awt.Shape;
0017: import java.awt.geom.Rectangle2D;
0018: import java.awt.image.ColorModel;
0019: import java.awt.image.SampleModel;
0020: import java.awt.image.Raster;
0021: import java.awt.image.RenderedImage;
0022: import java.awt.image.WritableRaster;
0023: import java.awt.image.renderable.ContextualRenderedImageFactory;
0024: import java.awt.image.renderable.ParameterBlock;
0025: import java.awt.image.renderable.RenderContext;
0026: import java.awt.image.renderable.RenderableImage;
0027: import java.io.ByteArrayOutputStream;
0028: import java.io.Serializable;
0029: import java.net.InetAddress;
0030: import java.rmi.Naming;
0031: import java.rmi.Remote;
0032: import java.rmi.RemoteException;
0033: import java.rmi.RMISecurityManager;
0034: import java.rmi.server.UnicastRemoteObject;
0035: import java.util.Collection;
0036: import java.util.Hashtable;
0037: import java.util.List;
0038: import java.util.Iterator;
0039: import java.util.Vector;
0040: import javax.media.jai.CollectionOp;
0041: import javax.media.jai.CollectionImage;
0042: import javax.media.jai.JAI;
0043: import javax.media.jai.OperationDescriptor;
0044: import javax.media.jai.OperationRegistry;
0045: import javax.media.jai.OpImage;
0046: import javax.media.jai.ParameterListDescriptor;
0047: import javax.media.jai.PlanarImage;
0048: import javax.media.jai.PropertyChangeEventJAI;
0049: import javax.media.jai.PropertySource;
0050: import javax.media.jai.RenderingChangeEvent;
0051: import javax.media.jai.RenderableOp;
0052: import javax.media.jai.RenderedOp;
0053: import javax.media.jai.registry.CRIFRegistry;
0054: import javax.media.jai.remote.JAIRMIDescriptor;
0055: import javax.media.jai.remote.RemoteImagingException;
0056: import javax.media.jai.remote.RemoteRenderedOp;
0057: import javax.media.jai.remote.NegotiableCapability;
0058: import javax.media.jai.remote.NegotiableCapabilitySet;
0059: import javax.media.jai.remote.SerializableRenderedImage;
0060: import javax.media.jai.remote.SerializableState;
0061: import javax.media.jai.remote.SerializerFactory;
0062: import javax.media.jai.tilecodec.TileCodecDescriptor;
0063: import javax.media.jai.tilecodec.TileCodecParameterList;
0064: import javax.media.jai.tilecodec.TileDecoderFactory;
0065: import javax.media.jai.tilecodec.TileEncoder;
0066: import javax.media.jai.tilecodec.TileEncoderFactory;
0067: import javax.media.jai.util.ImagingListener;
0068: import com.sun.media.jai.util.ImageUtil;
0069: import com.sun.media.jai.util.Service;
0070: import com.sun.media.jai.remote.JAIServerConfigurationSpi;
0071:
0072: /**
0073: * The server-side implementation of the ImageServer interface. A
0074: * JAIRMIImageServer has a RenderedImage source, acquired via one of three
0075: * setSource() methods. The first takes a RenderedImage directly as
0076: * its parameter; this image is simply copied over the network using
0077: * the normal RMI mechanisms. Note that not every image can be
0078: * transferred in this way -- for example, attempting to pass an
0079: * OpImage that uses native code or that depends on the availability
0080: * of a class not resident on the server as a parameter will cause an
0081: * exception to be thrown.
0082: *
0083: * <p> The second and third ways of setting sources make use of the
0084: * RenderedOp and RenderableOp classes to send a high-level
0085: * description of an image chain based on operation names. This
0086: * chain will be copied over to the server using RMI, where it will be
0087: * expanded into an OpImage chain using the server's registry. This
0088: * is the preferred method since it requires less data transfer and
0089: * offers a better chance of success. It may still fail if the
0090: * sources or parameters of any operation in the chain are not
0091: * serializable.
0092: *
0093: * <p> RMI requires all remote methods to declare `throws
0094: * RemoteException' in their signatures. It is up to the client to
0095: * deal with errors. A simple implementation of error handling may be
0096: * found in the RemoteRenderedImage class.
0097: *
0098: * <p> This class contains a main() method that should be run on the
0099: * server after starting the RMI registry. The registry will then
0100: * construct new instances of JAIRMIImageServer on demand.
0101: *
0102: * @see ImageServer
0103: * @see RenderedOp
0104: *
0105: * @since 1.1
0106: */
0107: public class JAIRMIImageServer extends UnicastRemoteObject implements
0108: ImageServer {
0109:
0110: private boolean DEBUG = true;
0111:
0112: /** Tag to represent a null property. */
0113: public static final Object NULL_PROPERTY = RMIImageImpl.NULL_PROPERTY;
0114:
0115: /** Identifier counter for the remote images. */
0116: private static long idCounter = 0;
0117:
0118: /**
0119: * The RenderedImage nodes hashed by an ID string which must be unique
0120: * across all possible clients of this object.
0121: */
0122: private static Hashtable nodes = new Hashtable();
0123:
0124: /**
0125: * Hashtable to store the negotiated values for each id.
0126: */
0127: private static Hashtable negotiated = new Hashtable();
0128:
0129: /**
0130: * Hashtable to store the number of references existing to a
0131: * particular id on this server.
0132: */
0133: private static Hashtable refCount = new Hashtable();
0134:
0135: /**
0136: * Retrieve a PlanarImage source from the Hashtable of sources.
0137: *
0138: * @param id The unique ID of the source.
0139: * @return The source.
0140: */
0141: private static PlanarImage getSource(Long id)
0142: throws RemoteException {
0143: Object obj = null;
0144: if (nodes == null || (obj = nodes.get(id)) == null) {
0145: throw new RemoteException(JaiI18N
0146: .getString("RMIImageImpl2"));
0147: }
0148: return (PlanarImage) obj;
0149: }
0150:
0151: /**
0152: * Retrieve a PropertySource from the Hashtable of PropertySources.
0153: *
0154: * @param id The unique ID of the source.
0155: * @return The PropertySource.
0156: */
0157: private static PropertySource getPropertySource(Long id)
0158: throws RemoteException {
0159:
0160: Object obj = nodes.get(id);
0161: return (PropertySource) obj;
0162: }
0163:
0164: /**
0165: * Constructs a JAIRMIImageServer with a source to be specified
0166: * later.
0167: */
0168: public JAIRMIImageServer(int serverport) throws RemoteException {
0169: super (serverport);
0170: }
0171:
0172: /**
0173: * Returns the identifier of the remote image. This method should be
0174: * called to return an identifier before any other methods are invoked.
0175: * The same ID must be used in all subsequent references to the remote
0176: * image.
0177: */
0178: public synchronized Long getRemoteID() throws RemoteException {
0179: return new Long(++idCounter);
0180: }
0181:
0182: /**
0183: * Disposes of any resouces allocated to the client object with
0184: * the specified ID.
0185: */
0186: public synchronized void dispose(Long id) throws RemoteException {
0187:
0188: int count = ((Integer) refCount.get(id)).intValue();
0189:
0190: if (count == 1) {
0191:
0192: // If this was the last reference, remove all Objects
0193: // associated with this id in various Hashtables.
0194: if (nodes != null) {
0195: nodes.remove(id);
0196: negotiated.remove(id);
0197: }
0198:
0199: refCount.remove(id);
0200:
0201: } else {
0202:
0203: // Decrement count of references to this id.
0204: count--;
0205: if (count == 0) {
0206: refCount.remove(id);
0207: }
0208: refCount.put(id, new Integer(count));
0209: }
0210: }
0211:
0212: /**
0213: * Increments the reference count for this id, i.e. increments the
0214: * number of RMIServerProxy objects that currently reference this id.
0215: */
0216: public void incrementRefCount(Long id) throws RemoteException {
0217: Integer iCount = (Integer) refCount.get(id);
0218: int count = 0;
0219: if (iCount != null) {
0220: count = iCount.intValue();
0221: }
0222: count++;
0223: refCount.put(id, new Integer(count));
0224: }
0225:
0226: /** Gets a property from the property set of this image. If the
0227: * property is undefined the constant NULL_PROPERTY is returned.
0228: */
0229: public Object getProperty(Long id, String name)
0230: throws RemoteException {
0231:
0232: PropertySource ps = getPropertySource(id);
0233: Object property = ps.getProperty(name);
0234:
0235: if (property == null
0236: || property.equals(java.awt.Image.UndefinedProperty)) {
0237: property = NULL_PROPERTY;
0238: }
0239:
0240: return property;
0241: }
0242:
0243: /**
0244: * Returns a list of names recognized by getProperty().
0245: *
0246: * @return an array of Strings representing property names.
0247: */
0248: public String[] getPropertyNames(Long id) throws RemoteException {
0249:
0250: PropertySource ps = getPropertySource(id);
0251: return ps.getPropertyNames();
0252:
0253: }
0254:
0255: /**
0256: * Returns a list of names recognized by getProperty().
0257: *
0258: * @return an array of Strings representing property names.
0259: */
0260: public String[] getPropertyNames(String opName)
0261: throws RemoteException {
0262:
0263: return (CRIFRegistry.get(null, opName)).getPropertyNames();
0264: }
0265:
0266: /** Returns the minimum X coordinate of the ImageServer. */
0267: public int getMinX(Long id) throws RemoteException {
0268: return getSource(id).getMinX();
0269: }
0270:
0271: /** Returns the smallest X coordinate to the right of the ImageServer. */
0272: public int getMaxX(Long id) throws RemoteException {
0273:
0274: return getSource(id).getMaxX();
0275: }
0276:
0277: /** Returns the minimum Y coordinate of the ImageServer. */
0278: public int getMinY(Long id) throws RemoteException {
0279:
0280: return getSource(id).getMinY();
0281: }
0282:
0283: /** Returns the smallest Y coordinate below the ImageServer. */
0284: public int getMaxY(Long id) throws RemoteException {
0285:
0286: return getSource(id).getMaxY();
0287: }
0288:
0289: /** Returns the width of the ImageServer. */
0290: public int getWidth(Long id) throws RemoteException {
0291:
0292: return getSource(id).getWidth();
0293: }
0294:
0295: /** Returns the height of the ImageServer. */
0296: public int getHeight(Long id) throws RemoteException {
0297:
0298: return getSource(id).getHeight();
0299: }
0300:
0301: /** Returns the width of a tile in pixels. */
0302: public int getTileWidth(Long id) throws RemoteException {
0303:
0304: return getSource(id).getTileWidth();
0305: }
0306:
0307: /** Returns the height of a tile in pixels. */
0308: public int getTileHeight(Long id) throws RemoteException {
0309:
0310: return getSource(id).getTileHeight();
0311: }
0312:
0313: /**
0314: * Returns the X coordinate of the upper-left pixel of tile (0, 0).
0315: */
0316: public int getTileGridXOffset(Long id) throws RemoteException {
0317:
0318: return getSource(id).getTileGridXOffset();
0319: }
0320:
0321: /**
0322: * Returns the Y coordinate of the upper-left pixel of tile (0, 0).
0323: */
0324: public int getTileGridYOffset(Long id) throws RemoteException {
0325:
0326: return getSource(id).getTileGridYOffset();
0327: }
0328:
0329: /** Returns the index of the leftmost column of tiles. */
0330: public int getMinTileX(Long id) throws RemoteException {
0331:
0332: return getSource(id).getMinTileX();
0333: }
0334:
0335: /**
0336: * Returns the number of tiles along the tile grid in the horizontal
0337: * direction.
0338: */
0339: public int getNumXTiles(Long id) throws RemoteException {
0340:
0341: return getSource(id).getNumXTiles();
0342: }
0343:
0344: /** Returns the index of the uppermost row of tiles. */
0345: public int getMinTileY(Long id) throws RemoteException {
0346:
0347: return getSource(id).getMinTileY();
0348: }
0349:
0350: /**
0351: * Returns the number of tiles along the tile grid in the vertical
0352: * direction.
0353: */
0354: public int getNumYTiles(Long id) throws RemoteException {
0355:
0356: return getSource(id).getNumYTiles();
0357: }
0358:
0359: /** Returns the index of the rightmost column of tiles. */
0360: public int getMaxTileX(Long id) throws RemoteException {
0361:
0362: return getSource(id).getMaxTileX();
0363: }
0364:
0365: /** Returns the index of the bottom row of tiles. */
0366: public int getMaxTileY(Long id) throws RemoteException {
0367:
0368: return getSource(id).getMaxTileY();
0369: }
0370:
0371: /** Returns the SampleModel associated with this image. */
0372: public SerializableState getSampleModel(Long id)
0373: throws RemoteException {
0374: return SerializerFactory.getState(getSource(id)
0375: .getSampleModel(), null);
0376: }
0377:
0378: /** Returns the ColorModel associated with this image. */
0379: public SerializableState getColorModel(Long id)
0380: throws RemoteException {
0381: return SerializerFactory.getState(
0382: getSource(id).getColorModel(), null);
0383: }
0384:
0385: /** Returns a Rectangle indicating the image bounds. */
0386: public Rectangle getBounds(Long id) throws RemoteException {
0387:
0388: return getSource(id).getBounds();
0389: }
0390:
0391: /**
0392: * Returns tile (x, y). Note that x and y are indices into the
0393: * tile array, not pixel locations. Unlike in the true RenderedImage
0394: * interface, the Raster that is returned should be considered a copy.
0395: *
0396: * @param id An ID for the source which must be unique across all clients.
0397: * @param tileX the X index of the requested tile in the tile array.
0398: * @param tileY the Y index of the requested tile in the tile array.
0399: * @return the tile as a Raster.
0400: */
0401: public SerializableState getTile(Long id, int tileX, int tileY)
0402: throws RemoteException {
0403:
0404: Raster r = getSource(id).getTile(tileX, tileY);
0405: return SerializerFactory.getState(r, null);
0406: }
0407:
0408: /**
0409: * Compresses tile (x, y) and returns the compressed tile's contents
0410: * as a byte array. Note that x and y are indices into the
0411: * tile array, not pixel locations. Unlike in the true RenderedImage
0412: * interface, the Raster that is returned should be considered a copy.
0413: *
0414: * @param id An ID for the source which must be unique across all clients.
0415: * @param x the x index of the requested tile in the tile array
0416: * @param y the y index of the requested tile in the tile array
0417: * @return a byte array containing the compressed tile contents.
0418: */
0419: public byte[] getCompressedTile(Long id, int x, int y)
0420: throws RemoteException {
0421:
0422: TileCodecParameterList tcpl = null;
0423: TileEncoderFactory tef = null;
0424: NegotiableCapability codecCap = null;
0425:
0426: if (negotiated != null) {
0427: codecCap = ((NegotiableCapabilitySet) negotiated.get(id))
0428: .getNegotiatedValue("tileCodec");
0429: }
0430:
0431: if (codecCap != null) {
0432:
0433: String category = codecCap.getCategory();
0434: String capabilityName = codecCap.getCapabilityName();
0435: List generators = codecCap.getGenerators();
0436:
0437: Class factory;
0438: for (Iterator i = generators.iterator(); i.hasNext();) {
0439:
0440: factory = (Class) i.next();
0441: if (tef == null
0442: && TileEncoderFactory.class
0443: .isAssignableFrom(factory)) {
0444: try {
0445: tef = (TileEncoderFactory) factory
0446: .newInstance();
0447: } catch (InstantiationException ie) {
0448: throw new RuntimeException(ie.getMessage());
0449: } catch (IllegalAccessException iae) {
0450: throw new RuntimeException(iae.getMessage());
0451: }
0452: }
0453: }
0454:
0455: if (tef == null) {
0456: throw new RuntimeException(JaiI18N
0457: .getString("JAIRMIImageServer0"));
0458: }
0459:
0460: TileCodecDescriptor tcd = (TileCodecDescriptor) JAI
0461: .getDefaultInstance().getOperationRegistry()
0462: .getDescriptor("tileEncoder", capabilityName);
0463:
0464: if (tcd.includesSampleModelInfo() == false
0465: || tcd.includesLocationInfo() == false) {
0466: throw new RuntimeException(JaiI18N
0467: .getString("JAIRMIImageServer1"));
0468: }
0469:
0470: ParameterListDescriptor pld = tcd
0471: .getParameterListDescriptor("tileEncoder");
0472:
0473: tcpl = new TileCodecParameterList(capabilityName,
0474: new String[] { "tileEncoder" }, pld);
0475:
0476: if (pld != null) {
0477:
0478: String paramNames[] = pld.getParamNames();
0479: String currParam;
0480: Object currValue;
0481:
0482: if (paramNames != null) {
0483: for (int i = 0; i < paramNames.length; i++) {
0484: currParam = paramNames[i];
0485: try {
0486: currValue = codecCap
0487: .getNegotiatedValue(currParam);
0488: } catch (IllegalArgumentException iae) {
0489: continue;
0490: }
0491: tcpl.setParameter(currParam, currValue);
0492: }
0493: }
0494: }
0495:
0496: Raster r = getSource(id).getTile(x, y);
0497: ByteArrayOutputStream stream = new ByteArrayOutputStream();
0498: TileEncoder encoder = tef.createEncoder(stream, tcpl, r
0499: .getSampleModel());
0500:
0501: try {
0502: encoder.encode(r);
0503: } catch (java.io.IOException ioe) {
0504: throw new RuntimeException(ioe.getMessage());
0505: }
0506:
0507: return stream.toByteArray();
0508: } else {
0509: throw new RuntimeException(JaiI18N
0510: .getString("JAIRMIImageServer2"));
0511: }
0512: }
0513:
0514: /**
0515: * Returns the entire image as a single Raster.
0516: *
0517: * @return a Raster containing a copy of this image's data.
0518: */
0519: public SerializableState getData(Long id) throws RemoteException {
0520: return SerializerFactory
0521: .getState(getSource(id).getData(), null);
0522: }
0523:
0524: /**
0525: * Returns an arbitrary rectangular region of the RenderedImage
0526: * in a Raster. The rectangle of interest will be clipped against
0527: * the image bounds.
0528: *
0529: * @param id An ID for the source which must be unique across all clients.
0530: * @param rect the region of the RenderedImage to be returned.
0531: * @return a SerializableState containing a copy of the desired data.
0532: */
0533: public SerializableState getData(Long id, Rectangle bounds)
0534: throws RemoteException {
0535: if (bounds == null) {
0536: return getData(id);
0537: } else {
0538: bounds = bounds.intersection(getBounds(id));
0539: return SerializerFactory.getState(getSource(id).getData(
0540: bounds), null);
0541: }
0542: }
0543:
0544: /**
0545: * Returns the same result as getData(Rectangle) would for the
0546: * same rectangular region.
0547: */
0548: public SerializableState copyData(Long id, Rectangle bounds)
0549: throws RemoteException {
0550: return getData(id, bounds);
0551: }
0552:
0553: /**
0554: * Creates a RenderedOp on the server side with a parameter block
0555: * empty of sources. The sources are set by separate calls depending
0556: * upon the type and serializabilty of the source.
0557: */
0558: public void createRenderedOp(Long id, String opName,
0559: ParameterBlock pb, SerializableState hints)
0560: throws RemoteException {
0561:
0562: RenderingHints rh = (RenderingHints) hints.getObject();
0563:
0564: // Check whether any of the parameters are Strings which represent
0565: // images either on this server or another server.
0566: JAIRMIUtil.checkServerParameters(pb, nodes);
0567:
0568: RenderedOp node = new RenderedOp(opName, pb, rh);
0569:
0570: // Remove all sinks so that no events are sent automatically
0571: // to the sinks
0572: node.removeSinks();
0573:
0574: nodes.put(id, node);
0575: }
0576:
0577: /**
0578: * Calls for Rendering of the Op and returns true if the RenderedOp
0579: * could be rendered else false
0580: */
0581: public boolean getRendering(Long id) throws RemoteException {
0582:
0583: RenderedOp op = getNode(id);
0584: if (op.getRendering() == null) {
0585: return false;
0586: } else {
0587: return true;
0588: }
0589: }
0590:
0591: /**
0592: * Retrieve a node from the hashtable
0593: *
0594: */
0595: public RenderedOp getNode(Long id) throws RemoteException {
0596: return (RenderedOp) nodes.get(id);
0597: }
0598:
0599: /**
0600: * Sets the source of the image as a RenderedImage on the server side
0601: */
0602: public synchronized void setRenderedSource(Long id,
0603: RenderedImage source, int index) throws RemoteException {
0604:
0605: PlanarImage pi = PlanarImage.wrapRenderedImage(source);
0606:
0607: Object obj = nodes.get(id);
0608:
0609: if (obj instanceof RenderedOp) {
0610: RenderedOp op = (RenderedOp) obj;
0611: op.setSource(pi, index);
0612: ((PlanarImage) op.getSourceObject(index)).removeSinks();
0613: } else if (obj instanceof RenderableOp) {
0614: ((RenderableOp) obj).setSource(pi, index);
0615: }
0616: }
0617:
0618: /**
0619: * Sets the source of the image as a RenderedOp on the server side
0620: */
0621: public synchronized void setRenderedSource(Long id,
0622: RenderedOp source, int index) throws RemoteException {
0623:
0624: Object obj = nodes.get(id);
0625: if (obj instanceof RenderedOp) {
0626: RenderedOp op = (RenderedOp) obj;
0627: op.setSource(source.getRendering(), index);
0628: ((PlanarImage) op.getSourceObject(index)).removeSinks();
0629: } else if (obj instanceof RenderableOp) {
0630: ((RenderableOp) obj)
0631: .setSource(source.getRendering(), index);
0632: }
0633: }
0634:
0635: /**
0636: * Sets the source of the image which is on the same
0637: * server
0638: */
0639: public synchronized void setRenderedSource(Long id, Long sourceId,
0640: int index) throws RemoteException {
0641:
0642: Object obj = nodes.get(id);
0643: if (obj instanceof RenderedOp) {
0644: RenderedOp op = (RenderedOp) obj;
0645: op.setSource(nodes.get(sourceId), index);
0646: ((PlanarImage) nodes.get(sourceId)).removeSinks();
0647: } else if (obj instanceof RenderableOp) {
0648: ((RenderableOp) obj).setSource(nodes.get(sourceId), index);
0649: }
0650: }
0651:
0652: /**
0653: * Sets the source of the image which is on a different
0654: * server
0655: */
0656: public synchronized void setRenderedSource(Long id, Long sourceId,
0657: String serverName, String opName, int index)
0658: throws RemoteException {
0659:
0660: Object obj = nodes.get(id);
0661:
0662: if (obj instanceof RenderedOp) {
0663: RenderedOp node = (RenderedOp) obj;
0664: node.setSource(new RMIServerProxy(
0665: (serverName + "::" + sourceId), opName, null),
0666: index);
0667: ((PlanarImage) node.getSourceObject(index)).removeSinks();
0668: } else if (obj instanceof RenderableOp) {
0669: ((RenderableOp) obj).setSource(new RMIServerProxy(
0670: (serverName + "::" + sourceId), opName, null),
0671: index);
0672: }
0673: }
0674:
0675: /// Renderable Mode Methods
0676:
0677: /**
0678: * Gets the minimum X coordinate of the rendering-independent image
0679: * stored against the given ID.
0680: *
0681: * @return the minimum X coordinate of the rendering-independent image
0682: * data.
0683: */
0684: public float getRenderableMinX(Long id) throws RemoteException {
0685:
0686: RenderableImage ri = (RenderableImage) nodes.get(id);
0687: return ri.getMinX();
0688: }
0689:
0690: /**
0691: * Gets the minimum Y coordinate of the rendering-independent image
0692: * stored against the given ID.
0693: *
0694: * @return the minimum X coordinate of the rendering-independent image
0695: * data.
0696: */
0697: public float getRenderableMinY(Long id) throws RemoteException {
0698: RenderableImage ri = (RenderableImage) nodes.get(id);
0699: return ri.getMinY();
0700: }
0701:
0702: /**
0703: * Gets the width (in user coordinate space) of the
0704: * <code>RenderableImage</code> stored against the given ID.
0705: *
0706: * @return the width of the renderable image in user coordinates.
0707: */
0708: public float getRenderableWidth(Long id) throws RemoteException {
0709: RenderableImage ri = (RenderableImage) nodes.get(id);
0710: return ri.getWidth();
0711: }
0712:
0713: /**
0714: * Gets the height (in user coordinate space) of the
0715: * <code>RenderableImage</code> stored against the given ID.
0716: *
0717: * @return the height of the renderable image in user coordinates.
0718: */
0719: public float getRenderableHeight(Long id) throws RemoteException {
0720: RenderableImage ri = (RenderableImage) nodes.get(id);
0721: return ri.getHeight();
0722: }
0723:
0724: /**
0725: * Creates a RenderedImage instance of this image with width w, and
0726: * height h in pixels. The RenderContext is built automatically
0727: * with an appropriate usr2dev transform and an area of interest
0728: * of the full image. All the rendering hints come from hints
0729: * passed in.
0730: *
0731: * <p> If w == 0, it will be taken to equal
0732: * Math.round(h*(getWidth()/getHeight())).
0733: * Similarly, if h == 0, it will be taken to equal
0734: * Math.round(w*(getHeight()/getWidth())). One of
0735: * w or h must be non-zero or else an IllegalArgumentException
0736: * will be thrown.
0737: *
0738: * <p> The created RenderedImage may have a property identified
0739: * by the String HINTS_OBSERVED to indicate which RenderingHints
0740: * were used to create the image. In addition any RenderedImages
0741: * that are obtained via the getSources() method on the created
0742: * RenderedImage may have such a property.
0743: *
0744: * @param w the width of rendered image in pixels, or 0.
0745: * @param h the height of rendered image in pixels, or 0.
0746: * @param hints a RenderingHints object containg hints.
0747: * @return a RenderedImage containing the rendered data.
0748: */
0749: public RenderedImage createScaledRendering(Long id, int w, int h,
0750: SerializableState hintsState) throws RemoteException {
0751:
0752: RenderableImage ri = (RenderableImage) nodes.get(id);
0753: RenderingHints hints = (RenderingHints) hintsState.getObject();
0754: RenderedImage rendering = ri.createScaledRendering(w, h, hints);
0755: if (rendering instanceof Serializable) {
0756: return rendering;
0757: } else {
0758: return new SerializableRenderedImage(rendering);
0759: }
0760: }
0761:
0762: /**
0763: * Returnd a RenderedImage instance of this image with a default
0764: * width and height in pixels. The RenderContext is built
0765: * automatically with an appropriate usr2dev transform and an area
0766: * of interest of the full image. The rendering hints are
0767: * empty. createDefaultRendering may make use of a stored
0768: * rendering for speed.
0769: *
0770: * @return a RenderedImage containing the rendered data.
0771: */
0772: public RenderedImage createDefaultRendering(Long id)
0773: throws RemoteException {
0774:
0775: RenderableImage ri = (RenderableImage) nodes.get(id);
0776: RenderedImage rendering = ri.createDefaultRendering();
0777: if (rendering instanceof Serializable) {
0778: return rendering;
0779: } else {
0780: return new SerializableRenderedImage(rendering);
0781: }
0782: }
0783:
0784: /**
0785: * Creates a RenderedImage that represented a rendering of this image
0786: * using a given RenderContext. This is the most general way to obtain a
0787: * rendering of a RenderableImage.
0788: *
0789: * <p> The created RenderedImage may have a property identified
0790: * by the String HINTS_OBSERVED to indicate which RenderingHints
0791: * (from the RenderContext) were used to create the image.
0792: * In addition any RenderedImages
0793: * that are obtained via the getSources() method on the created
0794: * RenderedImage may have such a property.
0795: *
0796: * @param renderContext the RenderContext to use to produce the rendering.
0797: * @return a RenderedImage containing the rendered data.
0798: */
0799: public RenderedImage createRendering(Long id,
0800: SerializableState renderContextState)
0801: throws RemoteException {
0802:
0803: RenderableImage ri = (RenderableImage) nodes.get(id);
0804: RenderContext renderContext = (RenderContext) renderContextState
0805: .getObject();
0806: RenderedImage rendering = ri.createRendering(renderContext);
0807: if (rendering instanceof Serializable) {
0808: return rendering;
0809: } else {
0810: return new SerializableRenderedImage(rendering);
0811: }
0812: }
0813:
0814: /**
0815: * Creates a RenderableOp on the server side with a parameter block
0816: * empty of sources. The sources are set by separate calls depending
0817: * upon the type and serializabilty of the source.
0818: */
0819: public synchronized void createRenderableOp(Long id, String opName,
0820: ParameterBlock pb) throws RemoteException {
0821:
0822: // XXX Since RMIServerProxy does not do a checkClientParameters, this
0823: // side obviously does not do the corresponding
0824: // checkServerParameters. Look at RMIServerProxy's renderable
0825: // constructor for reasoning. aastha, 09/26/01
0826:
0827: RenderableOp node = new RenderableOp(opName, pb);
0828: nodes.put(id, node);
0829: }
0830:
0831: /**
0832: * Calls for rendering of a RenderableOp with the given SerializableState
0833: */
0834: public synchronized Long getRendering(Long id, SerializableState rcs)
0835: throws RemoteException {
0836:
0837: RenderableOp op = (RenderableOp) nodes.get(id);
0838: PlanarImage pi = PlanarImage.wrapRenderedImage(op
0839: .createRendering((RenderContext) rcs.getObject()));
0840:
0841: Long renderingID = getRemoteID();
0842: nodes.put(renderingID, pi);
0843:
0844: // Put the op's negotiated result values for its rendering too.
0845: setServerNegotiatedValues(renderingID,
0846: (NegotiableCapabilitySet) negotiated.get(id));
0847: return renderingID;
0848: }
0849:
0850: /**
0851: * Sets the source of the image which is on the same
0852: * server
0853: */
0854: public synchronized void setRenderableSource(Long id,
0855: Long sourceId, int index) throws RemoteException {
0856:
0857: RenderableOp node = (RenderableOp) nodes.get(id);
0858: Object obj = nodes.get(sourceId);
0859: if (obj instanceof RenderableOp) {
0860: node.setSource((RenderableOp) obj, index);
0861: } else if (obj instanceof RenderedImage) {
0862: node.setSource(PlanarImage
0863: .wrapRenderedImage((RenderedImage) obj), index);
0864: }
0865: }
0866:
0867: /**
0868: * Sets the source of the image which is on a different
0869: * server
0870: */
0871: public synchronized void setRenderableSource(Long id,
0872: Long sourceId, String serverName, String opName, int index)
0873: throws RemoteException {
0874:
0875: RenderableOp node = (RenderableOp) nodes.get(id);
0876: node.setSource(new RMIServerProxy(
0877: (serverName + "::" + sourceId), opName, null), index);
0878:
0879: }
0880:
0881: /**
0882: * Sets the source of the image which is on a different
0883: * server
0884: */
0885: public synchronized void setRenderableRMIServerProxyAsSource(
0886: Long id, Long sourceId, String serverName, String opName,
0887: int index) throws RemoteException {
0888:
0889: RenderableOp node = (RenderableOp) nodes.get(id);
0890: node.setSource(new RenderableRMIServerProxy(serverName, opName,
0891: null, sourceId), index);
0892: }
0893:
0894: /**
0895: * when source is set to a RenderableOp and isnt supposed to be
0896: * rendered yet. like at the time of getBounds2D
0897: *
0898: * Sets the source of the image as a RenderableOp on the server side
0899: *
0900: */
0901: public synchronized void setRenderableSource(Long id,
0902: RenderableOp source, int index) throws RemoteException {
0903: RenderableOp op = (RenderableOp) nodes.get(id);
0904: op.setSource(source, index);
0905: }
0906:
0907: /**
0908: * Sets the source of the image as a RenderableImage on the server side
0909: */
0910: public synchronized void setRenderableSource(Long id,
0911: SerializableRenderableImage s, int index)
0912: throws RemoteException {
0913: RenderableOp op = (RenderableOp) nodes.get(id);
0914: op.setSource(s, index);
0915: }
0916:
0917: /**
0918: * Sets the source of the image as a RenderedImage on the server side
0919: */
0920: public synchronized void setRenderableSource(Long id,
0921: RenderedImage source, int index) throws RemoteException {
0922:
0923: PlanarImage pi = PlanarImage.wrapRenderedImage(source);
0924: RenderableOp op = (RenderableOp) nodes.get(id);
0925: op.setSource(pi, index);
0926: }
0927:
0928: /**
0929: * Maps the RenderContext for the remote Image
0930: */
0931: public SerializableState mapRenderContext(int id, Long nodeId,
0932: String operationName, SerializableState rcs)
0933: throws RemoteException {
0934:
0935: // Retrieve the RenderableOp for the rendering of which
0936: // the mapRenderContext call is being made.
0937: RenderableOp rop = (RenderableOp) nodes.get(nodeId);
0938:
0939: //Find the CRIF for the respective operation
0940: ContextualRenderedImageFactory crif = CRIFRegistry.get(rop
0941: .getRegistry(), operationName);
0942:
0943: if (crif == null) {
0944: throw new RuntimeException(JaiI18N
0945: .getString("JAIRMIImageServer3"));
0946: }
0947:
0948: RenderContext rc = crif.mapRenderContext(id,
0949: (RenderContext) rcs.getObject(), (ParameterBlock) rop
0950: .getParameterBlock(), rop);
0951: return SerializerFactory.getState(rc, null);
0952: }
0953:
0954: /**
0955: * Gets the Bounds2D of the specified Remote Image
0956: */
0957: public SerializableState getBounds2D(Long nodeId,
0958: String operationName) throws RemoteException {
0959:
0960: // Retrieve the RenderableOp for whose RIF
0961: // the mapRenderContext call is being made.
0962: RenderableOp rop = (RenderableOp) nodes.get(nodeId);
0963:
0964: //Find the CRIF for the respective operation
0965: ContextualRenderedImageFactory crif = CRIFRegistry.get(rop
0966: .getRegistry(), operationName);
0967:
0968: if (crif == null) {
0969: throw new RuntimeException(JaiI18N
0970: .getString("JAIRMIImageServer3"));
0971: }
0972:
0973: Rectangle2D r2D = crif.getBounds2D((ParameterBlock) rop
0974: .getParameterBlock());
0975:
0976: return SerializerFactory.getState(r2D, null);
0977: }
0978:
0979: /**
0980: * Returns <code>true</code> if successive renderings with the same
0981: * arguments may produce different results for this opName
0982: *
0983: * @return <code>false</code> indicating that the rendering is static.
0984: */
0985: public boolean isDynamic(String opName) throws RemoteException {
0986:
0987: return (CRIFRegistry.get(null, opName)).isDynamic();
0988: }
0989:
0990: /**
0991: * Returns <code>true</code> if successive renderings with the same
0992: * arguments may produce different results for the node represented
0993: * by the given id.
0994: */
0995: public boolean isDynamic(Long id) throws RemoteException {
0996:
0997: RenderableImage node = (RenderableImage) nodes.get(id);
0998: return node.isDynamic();
0999: }
1000:
1001: /**
1002: * Gets the operation names supported on the Server
1003: */
1004: public String[] getServerSupportedOperationNames()
1005: throws RemoteException {
1006: return JAI.getDefaultInstance().getOperationRegistry()
1007: .getDescriptorNames(OperationDescriptor.class);
1008: }
1009:
1010: /**
1011: * Gets the <code>OperationDescriptor</code>s of the operations
1012: * supported on this server.
1013: */
1014: public List getOperationDescriptors() throws RemoteException {
1015: return JAI.getDefaultInstance().getOperationRegistry()
1016: .getDescriptors(OperationDescriptor.class);
1017: }
1018:
1019: /**
1020: * Calculates the region over which two distinct renderings
1021: * of an operation may be expected to differ.
1022: *
1023: * <p> The class of the returned object will vary as a function of
1024: * the nature of the operation. For rendered and renderable two-
1025: * dimensional images this should be an instance of a class which
1026: * implements <code>java.awt.Shape</code>.
1027: *
1028: * @return The region over which the data of two renderings of this
1029: * operation may be expected to be invalid or <code>null</code>
1030: * if there is no common region of validity.
1031: */
1032: public synchronized SerializableState getInvalidRegion(Long id,
1033: ParameterBlock oldParamBlock, SerializableState oldRHints,
1034: ParameterBlock newParamBlock, SerializableState newRHints)
1035: throws RemoteException {
1036:
1037: RenderingHints oldHints = (RenderingHints) oldRHints
1038: .getObject();
1039: RenderingHints newHints = (RenderingHints) newRHints
1040: .getObject();
1041:
1042: RenderedOp op = (RenderedOp) nodes.get(id);
1043:
1044: OperationDescriptor od = (OperationDescriptor) JAI
1045: .getDefaultInstance().getOperationRegistry()
1046: .getDescriptor("rendered", op.getOperationName());
1047:
1048: boolean samePBs = false;
1049: if (oldParamBlock == newParamBlock)
1050: samePBs = true;
1051:
1052: Vector oldSources = oldParamBlock.getSources();
1053: oldParamBlock.removeSources();
1054: Vector oldReplacedSources = JAIRMIUtil.replaceIdWithSources(
1055: oldSources, nodes, op.getOperationName(), op
1056: .getRenderingHints());
1057: oldParamBlock.setSources(oldReplacedSources);
1058:
1059: if (samePBs) {
1060: newParamBlock = oldParamBlock;
1061: } else {
1062: Vector newSources = newParamBlock.getSources();
1063: newParamBlock.removeSources();
1064: Vector newReplacedSources = JAIRMIUtil
1065: .replaceIdWithSources(newSources, nodes, op
1066: .getOperationName(), op.getRenderingHints());
1067:
1068: newParamBlock.setSources(newReplacedSources);
1069: }
1070:
1071: Object invalidRegion = od.getInvalidRegion("rendered",
1072: oldParamBlock, oldHints, newParamBlock, newHints, op);
1073:
1074: SerializableState shapeState = SerializerFactory.getState(
1075: (Shape) invalidRegion, null);
1076:
1077: return shapeState;
1078: }
1079:
1080: /**
1081: * Returns a conservative estimate of the destination region that
1082: * can potentially be affected by the pixels of a rectangle of a
1083: * given source.
1084: *
1085: * @param id A <code>Long</code> identifying the node for whom
1086: * the destination region needs to be calculated .
1087: * @param sourceRect The <code>Rectangle</code> in source coordinates.
1088: * @param sourceIndex The index of the source image.
1089: *
1090: * @return A <code>Rectangle</code> indicating the potentially
1091: * affected destination region, or <code>null</code> if
1092: * the region is unknown.
1093: */
1094: public Rectangle mapSourceRect(Long id, Rectangle sourceRect,
1095: int sourceIndex) throws RemoteException {
1096:
1097: RenderedOp op = (RenderedOp) nodes.get(id);
1098: OpImage rendering = (OpImage) (op.getRendering());
1099: return rendering.mapSourceRect(sourceRect, sourceIndex);
1100: }
1101:
1102: /**
1103: * Returns a conservative estimate of the region of a specified
1104: * source that is required in order to compute the pixels of a
1105: * given destination rectangle.
1106: *
1107: * @param id A <code>Long</code> identifying the node for whom
1108: * the source region needs to be calculated .
1109: * @param destRect The <code>Rectangle</code> in destination coordinates.
1110: * @param sourceIndex The index of the source image.
1111: *
1112: * @return A <code>Rectangle</code> indicating the required source region.
1113: */
1114: public Rectangle mapDestRect(Long id, Rectangle destRect,
1115: int sourceIndex) throws RemoteException {
1116:
1117: RenderedOp op = (RenderedOp) nodes.get(id);
1118: OpImage rendering = (OpImage) (op.getRendering());
1119: return rendering.mapDestRect(destRect, sourceIndex);
1120: }
1121:
1122: /**
1123: * A method that handles the given event.
1124: */
1125: public synchronized Long handleEvent(Long renderedOpID,
1126: String propName, Object oldValue, Object newValue)
1127: throws RemoteException {
1128:
1129: RenderedOp op = (RenderedOp) nodes.get(renderedOpID);
1130: PlanarImage rendering = op.getRendering();
1131:
1132: // Get a new unique ID
1133: Long id = getRemoteID();
1134: // Cache the old rendering against the new id
1135: nodes.put(id, rendering);
1136:
1137: // Put the op's negotiated result values for its rendering too.
1138: setServerNegotiatedValues(id,
1139: (NegotiableCapabilitySet) negotiated.get(renderedOpID));
1140:
1141: // A PropertyChangeEventJAI with name "operationregistry",
1142: // "protocolname", "protocolandservername" or "servername" should
1143: // never be received here, since it is handled entirely on the
1144: // client side, so we don't handle those here.
1145:
1146: if (propName.equals("operationname")) {
1147:
1148: op.setOperationName((String) newValue);
1149:
1150: } else if (propName.equals("parameterblock")) {
1151:
1152: ParameterBlock newPB = (ParameterBlock) newValue;
1153: Vector newSrcs = newPB.getSources();
1154: newPB.removeSources();
1155:
1156: JAIRMIUtil.checkServerParameters(newPB, nodes);
1157:
1158: Vector replacedSources = JAIRMIUtil.replaceIdWithSources(
1159: newSrcs, nodes, op.getOperationName(), op
1160: .getRenderingHints());
1161: newPB.setSources(replacedSources);
1162:
1163: op.setParameterBlock(newPB);
1164:
1165: // Remove the newly created sinks of the srcs in the newPB
1166: Vector newSources = newPB.getSources();
1167: if (newSources != null && newSources.size() > 0) {
1168: Iterator it = newSources.iterator();
1169: while (it.hasNext()) {
1170: Object src = it.next();
1171: if (src instanceof PlanarImage) {
1172: ((PlanarImage) src).removeSinks();
1173: } else if (src instanceof CollectionImage) {
1174: ((CollectionImage) src).removeSinks();
1175: }
1176: }
1177: }
1178:
1179: } else if (propName.equals("sources")) {
1180:
1181: Vector replacedSources = JAIRMIUtil.replaceIdWithSources(
1182: (Vector) newValue, nodes, op.getOperationName(), op
1183: .getRenderingHints());
1184: op.setSources(replacedSources);
1185:
1186: // Remove the newly created sinks for the replacedSources
1187: if (replacedSources != null && replacedSources.size() > 0) {
1188: Iterator it = replacedSources.iterator();
1189: while (it.hasNext()) {
1190: Object src = it.next();
1191: if (src instanceof PlanarImage) {
1192: ((PlanarImage) src).removeSinks();
1193: } else if (src instanceof CollectionImage) {
1194: ((CollectionImage) src).removeSinks();
1195: }
1196: }
1197: }
1198:
1199: } else if (propName.equals("parameters")) {
1200:
1201: Vector parameters = (Vector) newValue;
1202: JAIRMIUtil.checkServerParameters(parameters, nodes);
1203: op.setParameters(parameters);
1204:
1205: } else if (propName.equals("renderinghints")) {
1206:
1207: SerializableState newState = (SerializableState) newValue;
1208: op.setRenderingHints((RenderingHints) newState.getObject());
1209: }
1210:
1211: return id;
1212: }
1213:
1214: /**
1215: * A method that handles a change in one of it's source's rendering,
1216: * i.e. a change that would be signalled by RenderingChangeEvent.
1217: */
1218: public synchronized Long handleEvent(Long renderedOpID,
1219: int srcIndex, SerializableState srcInvalidRegion,
1220: Object oldRendering) throws RemoteException {
1221:
1222: RenderedOp op = (RenderedOp) nodes.get(renderedOpID);
1223: PlanarImage rendering = op.getRendering();
1224:
1225: // Get a new unique ID
1226: Long id = getRemoteID();
1227: // Cache the old rendering against the new id
1228: nodes.put(id, rendering);
1229:
1230: // Put the op's negotiated result values for its rendering too.
1231: setServerNegotiatedValues(id,
1232: (NegotiableCapabilitySet) negotiated.get(renderedOpID));
1233:
1234: PlanarImage oldSrcRendering = null, newSrcRendering = null;
1235: String serverNodeDesc = null;
1236: Object src = null;
1237:
1238: if (oldRendering instanceof String) {
1239:
1240: serverNodeDesc = (String) oldRendering;
1241: int index = serverNodeDesc.indexOf("::");
1242: boolean diffServer = index != -1;
1243:
1244: if (diffServer) {
1245: // Create an RMIServerProxy to access the node on a
1246: // different server
1247: oldSrcRendering = new RMIServerProxy(serverNodeDesc, op
1248: .getOperationName(), op.getRenderingHints());
1249: } else {
1250:
1251: src = nodes.get(Long.valueOf(serverNodeDesc));
1252:
1253: if (src instanceof RenderedOp) {
1254: oldSrcRendering = ((RenderedOp) src).getRendering();
1255: } else {
1256: oldSrcRendering = PlanarImage
1257: .wrapRenderedImage((RenderedImage) src);
1258: }
1259: }
1260:
1261: } else {
1262: oldSrcRendering = PlanarImage
1263: .wrapRenderedImage((RenderedImage) oldRendering);
1264: }
1265:
1266: Object srcObj = op.getSource(srcIndex);
1267: if (srcObj instanceof RenderedOp) {
1268: newSrcRendering = ((RenderedOp) srcObj).getRendering();
1269: } else if (srcObj instanceof RenderedImage) {
1270: newSrcRendering = PlanarImage
1271: .wrapRenderedImage((RenderedImage) srcObj);
1272: }
1273:
1274: Shape invalidRegion = (Shape) srcInvalidRegion.getObject();
1275:
1276: RenderingChangeEvent rcEvent = new RenderingChangeEvent(
1277: (RenderedOp) op.getSource(srcIndex), oldSrcRendering,
1278: newSrcRendering, invalidRegion);
1279: op.propertyChange(rcEvent);
1280:
1281: return id;
1282: }
1283:
1284: /**
1285: * Returns the server's capabilities. Currently the only capabilities
1286: * that are reported are those dealing with TileCodecs.
1287: */
1288: public synchronized NegotiableCapabilitySet getServerCapabilities() {
1289:
1290: OperationRegistry registry = JAI.getDefaultInstance()
1291: .getOperationRegistry();
1292:
1293: // Note that only the tileEncoder capabilities are returned from
1294: // this method since there is no way to distinguish between NC's
1295: // for the encoder and the decoder.
1296: String modeName = "tileEncoder";
1297: String[] descriptorNames = registry
1298: .getDescriptorNames(modeName);
1299: TileEncoderFactory tef = null;
1300:
1301: // Only non-preference NC's can be added.
1302: NegotiableCapabilitySet capabilities = new NegotiableCapabilitySet(
1303: false);
1304:
1305: Iterator it;
1306: for (int i = 0; i < descriptorNames.length; i++) {
1307:
1308: it = registry.getFactoryIterator(modeName,
1309: descriptorNames[i]);
1310: for (; it.hasNext();) {
1311: tef = (TileEncoderFactory) it.next();
1312: capabilities.add(tef.getEncodeCapability());
1313: }
1314: }
1315:
1316: return capabilities;
1317: }
1318:
1319: /**
1320: * Informs the server of the negotiated values that are the result of
1321: * a successful negotiation.
1322: *
1323: * @param negotiatedValues The result of the negotiation.
1324: */
1325: public void setServerNegotiatedValues(Long id,
1326: NegotiableCapabilitySet negotiatedValues)
1327: throws RemoteException {
1328: if (negotiatedValues != null)
1329: negotiated.put(id, negotiatedValues);
1330: else
1331: negotiated.remove(id);
1332: }
1333:
1334: /**
1335: * Starts a server on a given port. The RMI registry must be running
1336: * on the server host.
1337: *
1338: * <p> The usage of this class is
1339: *
1340: * <pre>
1341: * java -Djava.rmi.server.codebase=file:$JAI/lib/jai.jar \
1342: * -Djava.rmi.server.useCodebaseOnly=false \
1343: * -Djava.security.policy=\
1344: * file:`pwd`/policy com.sun.media.jai.rmi.JAIRMIImageServer \
1345: * [-host hostName] [-port portNumber]
1346: * </pre>
1347: *
1348: * The default host is the local host and the default port is 1099.
1349: *
1350: * @param args the port number as a command-line argument.
1351: */
1352: public static void main(String[] args) {
1353:
1354: // Set the security manager.
1355: if (System.getSecurityManager() == null) {
1356: System.setSecurityManager(new RMISecurityManager());
1357: }
1358:
1359: // Load all JAIServerConfigurationSpi implementations on the CLASSPATH
1360: Iterator spiIter = Service
1361: .providers(JAIServerConfigurationSpi.class);
1362: JAI jai = JAI.getDefaultInstance();
1363:
1364: while (spiIter.hasNext()) {
1365:
1366: JAIServerConfigurationSpi serverSpi = (JAIServerConfigurationSpi) spiIter
1367: .next();
1368: serverSpi.updateServer(jai);
1369: }
1370:
1371: // Set the host name and port number.
1372: String host = null;
1373: int rmiRegistryPort = 1099; // default port is 1099
1374: int serverport = 0;
1375:
1376: if (args.length != 0) {
1377:
1378: String value;
1379:
1380: for (int i = 0; i < args.length; i++) {
1381:
1382: if (args[i].equalsIgnoreCase("-help")) {
1383:
1384: System.out
1385: .println("Usage: java -Djava.rmi.server.codebase=file:$JAI/lib/jai.jar \\");
1386: System.out
1387: .println("-Djava.rmi.server.useCodebaseOnly=false \\");
1388: System.out
1389: .println("-Djava.security.policy=file:`pwd`/policy \\");
1390: System.out
1391: .println("com.sun.media.jai.rmi.JAIRMIImageServer \\");
1392: System.out.println("\nwhere options are:");
1393: System.out
1394: .println("\t-host <string> The server name or server IP address");
1395: System.out
1396: .println("\t-port <integer> The port that rmiregistry is running on");
1397: System.out
1398: .println("\t-rmiRegistryPort <integer> Same as -port option");
1399: System.out
1400: .println("\t-serverPort <integer> The port that the server should listen on, for connections from clients");
1401: System.out
1402: .println("\t-cacheMemCapacity <long> The memory capacity in bytes.");
1403: System.out
1404: .println("\t-cacheMemThreshold <float> The memory threshold, which is the fractional amount of cache memory to retain during tile removal");
1405: System.out
1406: .println("\t-disableDefaultCache Disable use of default tile cache. Tiles are not stored.");
1407: System.out
1408: .println("\t-schedulerParallelism <integer> The degree of parallelism of the default TileScheduler");
1409: System.out
1410: .println("\t-schedulerPrefetchParallelism <integer> The degree of parallelism of the default TileScheduler for tile prefetching");
1411: System.out
1412: .println("\t-schedulerPriority <integer> The priority of tile scheduling for the default TileScheduler");
1413: System.out
1414: .println("\t-schedulerPrefetchPriority <integer> The priority of tile prefetch scheduling for the default TileScheduler");
1415: System.out
1416: .println("\t-defaultTileSize <integer>x<integer> The default tile dimensions in the form <xSize>x<ySize>");
1417: System.out
1418: .println("\t-defaultRenderingSize <integer>x<integer> The default size to render a RenderableImage to, in the form <xSize>x<ySize>");
1419: System.out
1420: .println("\t-serializeDeepCopy <boolean> Whether a deep copy of the image data should be used when serializing images");
1421: System.out
1422: .println("\t-tileCodecFormat <string> The default format to be used for tile serialization via TileCodecs");
1423: System.out
1424: .println("\t-retryInterval <integer> The retry interval value to be used for dealing with network errors during remote imaging");
1425: System.out
1426: .println("\t-numRetries <integer> The number of retries to be used for dealing with network errors during remote imaging");
1427:
1428: } else if (args[i].equalsIgnoreCase("-host")) {
1429:
1430: host = args[++i];
1431:
1432: } else if (args[i].equalsIgnoreCase("-port")
1433: || args[i].equalsIgnoreCase("-rmiRegistryPort")) {
1434:
1435: rmiRegistryPort = Integer.parseInt(args[++i]);
1436:
1437: } else if (args[i].equalsIgnoreCase("-serverport")) {
1438:
1439: serverport = Integer.parseInt(args[++i]);
1440:
1441: } else if (args[i]
1442: .equalsIgnoreCase("-cacheMemCapacity")) {
1443:
1444: jai.getTileCache().setMemoryCapacity(
1445: Long.parseLong(args[++i]));
1446:
1447: } else if (args[i]
1448: .equalsIgnoreCase("-cacheMemThreshold")) {
1449:
1450: jai.getTileCache().setMemoryThreshold(
1451: Float.parseFloat(args[++i]));
1452:
1453: } else if (args[i]
1454: .equalsIgnoreCase("-disableDefaultCache")) {
1455:
1456: jai.disableDefaultTileCache();
1457:
1458: } else if (args[i]
1459: .equalsIgnoreCase("-schedulerParallelism")) {
1460:
1461: jai.getTileScheduler().setParallelism(
1462: Integer.parseInt(args[++i]));
1463:
1464: } else if (args[i]
1465: .equalsIgnoreCase("-schedulerPrefetchParallelism")) {
1466:
1467: jai.getTileScheduler().setPrefetchParallelism(
1468: Integer.parseInt(args[++i]));
1469:
1470: } else if (args[i]
1471: .equalsIgnoreCase("-schedulerPriority")) {
1472:
1473: jai.getTileScheduler().setPriority(
1474: Integer.parseInt(args[++i]));
1475:
1476: } else if (args[i]
1477: .equalsIgnoreCase("-schedulerPrefetchPriority")) {
1478:
1479: jai.getTileScheduler().setPrefetchPriority(
1480: Integer.parseInt(args[++i]));
1481:
1482: } else if (args[i].equalsIgnoreCase("-defaultTileSize")) {
1483:
1484: value = args[++i].toLowerCase();
1485: int xpos = value.indexOf("x");
1486: int xSize = Integer.parseInt(value.substring(0,
1487: xpos));
1488: int ySize = Integer.parseInt(value
1489: .substring(xpos + 1));
1490:
1491: jai.setDefaultTileSize(new Dimension(xSize, ySize));
1492:
1493: } else if (args[i]
1494: .equalsIgnoreCase("-defaultRenderingSize")) {
1495:
1496: value = args[++i].toLowerCase();
1497: int xpos = value.indexOf("x");
1498: int xSize = Integer.parseInt(value.substring(0,
1499: xpos));
1500: int ySize = Integer.parseInt(value
1501: .substring(xpos + 1));
1502:
1503: jai.setDefaultRenderingSize(new Dimension(xSize,
1504: ySize));
1505:
1506: } else if (args[i]
1507: .equalsIgnoreCase("-serializeDeepCopy")) {
1508:
1509: jai.setRenderingHint(JAI.KEY_SERIALIZE_DEEP_COPY,
1510: Boolean.valueOf(args[++i]));
1511:
1512: } else if (args[i].equalsIgnoreCase("-tileCodecFormat")) {
1513:
1514: jai.setRenderingHint(JAI.KEY_TILE_CODEC_FORMAT,
1515: args[++i]);
1516:
1517: } else if (args[i].equalsIgnoreCase("-retryInterval")) {
1518:
1519: jai.setRenderingHint(JAI.KEY_RETRY_INTERVAL,
1520: Integer.valueOf(args[++i]));
1521:
1522: } else if (args[i].equalsIgnoreCase("-numRetries")) {
1523:
1524: jai.setRenderingHint(JAI.KEY_NUM_RETRIES, Integer
1525: .valueOf(args[++i]));
1526: }
1527: }
1528: }
1529:
1530: // Default to the local host if the host was not specified.
1531: if (host == null) {
1532: try {
1533: host = InetAddress.getLocalHost().getHostAddress();
1534: } catch (java.net.UnknownHostException e) {
1535: String message = JaiI18N.getString("RMIImageImpl1");
1536: sendExceptionToListener(message,
1537: new RemoteImagingException(message, e));
1538: /*
1539: System.err.println(JaiI18N.getString("RMIImageImpl1") +
1540: e.getMessage());
1541: e.printStackTrace();
1542: */
1543: }
1544: }
1545:
1546: System.out.println(JaiI18N.getString("RMIImageImpl3") + " "
1547: + host + ":" + rmiRegistryPort);
1548:
1549: try {
1550: JAIRMIImageServer im = new JAIRMIImageServer(serverport);
1551: String serverName = new String("rmi://" + host + ":"
1552: + rmiRegistryPort + "/"
1553: + JAIRMIDescriptor.IMAGE_SERVER_BIND_NAME);
1554: System.out.println(JaiI18N.getString("RMIImageImpl4")
1555: + " \"" + serverName + "\".");
1556: Naming.rebind(serverName, im);
1557: System.out.println(JaiI18N.getString("RMIImageImpl5"));
1558: } catch (Exception e) {
1559: String message = JaiI18N.getString("RMIImageImpl1");
1560: sendExceptionToListener(message,
1561: new RemoteImagingException(message, e));
1562: /*
1563: System.err.println(JaiI18N.getString("RMIImageImpl0") +
1564: e.getMessage());
1565: e.printStackTrace();
1566: */
1567: }
1568: }
1569:
1570: private static void sendExceptionToListener(String message,
1571: Exception e) {
1572: ImagingListener listener = ImageUtil
1573: .getImagingListener((RenderingHints) null);
1574: listener.errorOccurred(message, new RemoteImagingException(
1575: message, e), JAIRMIImageServer.class, false);
1576: }
1577: }
|