001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.ext.awt.image.renderable;
020:
021: import java.awt.RenderingHints;
022: import java.awt.Shape;
023: import java.awt.geom.Rectangle2D;
024: import java.awt.image.RenderedImage;
025: import java.awt.image.renderable.RenderContext;
026: import java.util.Map;
027: import java.util.Vector;
028:
029: /**
030: * This class allows for the return of a proxy object quickly, while a
031: * heavy weight object is constrcuted in a background Thread. This
032: * proxy object will then block if any methods are called on it that
033: * require talking to the source object.
034: *
035: * This is actually a particular instance of a very general pattern
036: * this is probably best represented using the Proxy class in the
037: * Reflection APIs.
038: *
039: * @version $Id: DeferRable.java 478363 2006-11-22 23:01:13Z dvholten $
040: */
041: public class DeferRable implements Filter {
042: Filter src;
043: Rectangle2D bounds;
044: Map props;
045:
046: /**
047: * Constructor takes nothing
048: */
049: public DeferRable() {
050: }
051:
052: /**
053: * Key method that blocks if the src has not yet been provided.
054: */
055: public synchronized Filter getSource() {
056: while (src == null) {
057: try {
058: // Wait for someone to set src.
059: wait();
060: } catch (InterruptedException ie) {
061: // Loop around again see if src is set now...
062: }
063: }
064: return src;
065: }
066:
067: /**
068: * Key method that sets the src. The source can only
069: * be set once (this makes sense given the intent of the
070: * class is to stand in for a real object, so swaping that
071: * object isn't a good idea.
072: *
073: * This will wake all the threads that might be waiting for
074: * the source to be set.
075: */
076: public synchronized void setSource(Filter src) {
077: // Only let them set Source once.
078: if (this .src != null)
079: return;
080: this .src = src;
081: this .bounds = src.getBounds2D();
082: notifyAll();
083: }
084:
085: public synchronized void setBounds(Rectangle2D bounds) {
086: if (this .bounds != null)
087: return;
088: this .bounds = bounds;
089: notifyAll();
090: }
091:
092: public synchronized void setProperties(Map props) {
093: this .props = props;
094: notifyAll();
095: }
096:
097: public long getTimeStamp() {
098: return getSource().getTimeStamp();
099: }
100:
101: public Vector getSources() {
102: return getSource().getSources();
103: }
104:
105: /**
106: * Forward the call (blocking until source is set if need be).
107: */
108: public boolean isDynamic() {
109: return getSource().isDynamic();
110: }
111:
112: /**
113: * Implement the baseclass method to call getSource() so
114: * it will block until we have a real source.
115: */
116: public Rectangle2D getBounds2D() {
117: synchronized (this ) {
118: while ((src == null) && (bounds == null)) {
119: try {
120: // Wait for someone to set bounds.
121: wait();
122: } catch (InterruptedException ie) {
123: // Loop around again see if src is set now...
124: }
125: }
126: }
127: if (src != null)
128: return src.getBounds2D();
129: return bounds;
130: }
131:
132: public float getMinX() {
133: return (float) getBounds2D().getX();
134: }
135:
136: public float getMinY() {
137: return (float) getBounds2D().getY();
138: }
139:
140: public float getWidth() {
141: return (float) getBounds2D().getWidth();
142: }
143:
144: public float getHeight() {
145: return (float) getBounds2D().getHeight();
146: }
147:
148: /**
149: * Forward the call (blocking until source is set if need be).
150: */
151: public Object getProperty(String name) {
152: synchronized (this ) {
153: while ((src == null) && (props == null)) {
154: try {
155: // Wait for someone to set src | props
156: wait();
157: } catch (InterruptedException ie) {
158: }
159: }
160: }
161: if (src != null)
162: return src.getProperty(name);
163: return props.get(name);
164: }
165:
166: /**
167: * Forward the call (blocking until source is set if need be).
168: */
169: public String[] getPropertyNames() {
170: synchronized (this ) {
171: while ((src == null) && (props == null)) {
172: try {
173: // Wait for someone to set src | props
174: wait();
175: } catch (InterruptedException ie) {
176: }
177: }
178: }
179: if (src != null)
180: return src.getPropertyNames();
181:
182: String[] ret = new String[props.size()];
183: props.keySet().toArray(ret);
184: return ret;
185: }
186:
187: /**
188: * Forward the call (blocking until source is set if need be).
189: */
190: public RenderedImage createDefaultRendering() {
191: return getSource().createDefaultRendering();
192: }
193:
194: /**
195: * Forward the call (blocking until source is set if need be).
196: */
197: public RenderedImage createScaledRendering(int w, int h,
198: RenderingHints hints) {
199: return getSource().createScaledRendering(w, h, hints);
200: }
201:
202: /**
203: * Forward the call (blocking until source is set if need be).
204: */
205: public RenderedImage createRendering(RenderContext rc) {
206: return getSource().createRendering(rc);
207: }
208:
209: /**
210: * Forward the call (blocking until source is set if need be).
211: */
212: public Shape getDependencyRegion(int srcIndex, Rectangle2D outputRgn) {
213: return getSource().getDependencyRegion(srcIndex, outputRgn);
214: }
215:
216: /**
217: * Forward the call (blocking until source is set if need be).
218: */
219: public Shape getDirtyRegion(int srcIndex, Rectangle2D inputRgn) {
220: return getSource().getDirtyRegion(srcIndex, inputRgn);
221: }
222: }
|