001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.base.ui;
039:
040: import java.io.InputStream;
041: import java.lang.reflect.Method;
042: import java.util.Map;
043: import org.millstone.base.terminal.UploadStream;
044: import org.millstone.base.terminal.PaintTarget;
045: import org.millstone.base.terminal.PaintException;
046: import java.io.IOException;
047: import java.io.OutputStream;
048:
049: /** Component for client file uploading.
050: *
051: * @author IT Mill Ltd.
052: * @version 3.1.1
053: * @since 3.0
054: */
055: public class Upload extends AbstractComponent implements
056: Component.Focusable {
057:
058: /** Upload buffer size. */
059: private static final int BUFFER_SIZE = 64 * 1024; // 64k
060:
061: /** Should the field be focused on next repaint */
062: private boolean focus = false;
063:
064: /** The tab order number of this field */
065: private int tabIndex = 0;
066:
067: /** The output of the upload is redirected to this receiver. */
068: private Receiver receiver;
069:
070: private long focusableId = -1;
071:
072: /* TODO: Add a default constructor, receive to temp file. */
073:
074: /** Creates a new instance of Upload that redirects the
075: * uploaded data to given stream.
076: *
077: */
078: public Upload(String caption, Receiver uploadReceiver) {
079: this .focusableId = Window.getNewFocusableId(this );
080: setCaption(caption);
081: receiver = uploadReceiver;
082: }
083:
084: /** Get component type.
085: * @return Component type as string.
086: */
087: public String getTag() {
088: return "upload";
089: }
090:
091: /** Invoked when the value of a variable has changed. */
092: public void changeVariables(Object source, Map variables) {
093:
094: // Check the variable name
095: if (!variables.containsKey("stream"))
096: return;
097:
098: // Get the upload stream
099: UploadStream upload = (UploadStream) variables.get("stream");
100:
101: // Get file properties
102: String filename = upload.getContentName();
103: String type = upload.getContentType();
104:
105: // Get the output target stream
106: OutputStream out = receiver.receiveUpload(filename, type);
107: if (out == null)
108: throw new RuntimeException(
109: "Error getting outputstream from upload receiver");
110:
111: InputStream in = upload.getStream();
112: byte buffer[] = new byte[BUFFER_SIZE];
113: int bytesRead = 0;
114: long totalBytes = 0;
115: try {
116: while ((bytesRead = in.read(buffer)) > 0) {
117: out.write(buffer, 0, bytesRead);
118: totalBytes += bytesRead;
119: }
120:
121: // Download successfull
122: out.close();
123: fireUploadSuccess(filename, type, totalBytes);
124:
125: } catch (IOException e) {
126:
127: // Download interrupted
128: fireUploadInterrupted(filename, type, totalBytes);
129: }
130: }
131:
132: /** Paint the content of this component.
133: * @param target Target to paint the content on.
134: * @throws PaintException The paint operation failed.
135: */
136: public void paintContent(PaintTarget target) throws PaintException {
137: // The field should be focused
138: if (focus)
139: target.addAttribute("focus", true);
140:
141: // The tab ordering number
142: if (this .tabIndex >= 0)
143: target.addAttribute("tabindex", this .tabIndex);
144:
145: target.addUploadStreamVariable(this , "stream");
146: }
147:
148: /** Notify all upload listeners */
149: private void notifyListeners() {
150:
151: }
152:
153: /** Interface that must be implemented by the upload receivers.
154: * @author IT Mill Ltd.
155: * @version 3.1.1
156: * @since 3.0
157: */
158: public interface Receiver {
159:
160: /** Invoked when a new upload arrives.
161: * @param filename The desired filename of the upload, usually as specified by the client.
162: * @param MIMEType The MIME type of the uploaded file.
163: * @return Stream to which the uploaded file should be written.
164: */
165: public OutputStream receiveUpload(String filename,
166: String MIMEType);
167: }
168:
169: /* Upload events ************************************************ */
170:
171: private static final Method UPLOAD_FINISHED_METHOD;
172: private static final Method UPLOAD_FAILED_METHOD;
173: private static final Method UPLOAD_SUCCEEDED_METHOD;
174:
175: static {
176: try {
177: UPLOAD_FINISHED_METHOD = FinishedListener.class
178: .getDeclaredMethod("uploadFinished",
179: new Class[] { FinishedEvent.class });
180: UPLOAD_FAILED_METHOD = FailedListener.class
181: .getDeclaredMethod("uploadFailed",
182: new Class[] { FailedEvent.class });
183: UPLOAD_SUCCEEDED_METHOD = SucceededListener.class
184: .getDeclaredMethod("uploadSucceeded",
185: new Class[] { SucceededEvent.class });
186: } catch (java.lang.NoSuchMethodException e) {
187: // This should never happen
188: throw new java.lang.RuntimeException("Internal error");
189: }
190: }
191:
192: /** Upload.Received event is sent when the upload receives a file,
193: * regardless if the receival was successfull.
194: * @author IT Mill Ltd.
195: * @version 3.1.1
196: * @since 3.0
197: */
198: public class FinishedEvent extends Component.Event {
199:
200: /**
201: * Serial generated by eclipse.
202: */
203: private static final long serialVersionUID = 3257288015385670969L;
204:
205: /** Length of the received file. */
206: private long length;
207:
208: /** MIME type of the received file. */
209: private String type;
210:
211: /** Received file name */
212: private String filename;
213:
214: public FinishedEvent(Upload source, String filename,
215: String MIMEType, long length) {
216: super (source);
217: this .type = MIMEType;
218: this .filename = filename;
219: this .length = length;
220: }
221:
222: /** Upload where the event occurred
223: * @return Source of the event.
224: */
225: public Upload getUpload() {
226: return (Upload) getSource();
227: }
228:
229: /**
230: * Returns the filename.
231: */
232: public String getFilename() {
233: return filename;
234: }
235:
236: /**
237: * Returns the length.
238: */
239: public long getLength() {
240: return length;
241: }
242:
243: /**
244: * Returns the type.
245: */
246: public String getMIMEType() {
247: return type;
248: }
249:
250: }
251:
252: /** Upload.Interrupted event is sent when the upload is received, but the
253: * reception is interrupted for some reason.
254: * @author IT Mill Ltd.
255: * @version 3.1.1
256: * @since 3.0
257: */
258: public class FailedEvent extends FinishedEvent {
259:
260: /**
261: * Serial generated by eclipse.
262: */
263: private static final long serialVersionUID = 3833746590157386293L;
264:
265: public FailedEvent(Upload source, String filename,
266: String MIMEType, long length) {
267: super (source, filename, MIMEType, length);
268: }
269:
270: }
271:
272: /** Upload.Success event is sent when the upload is received successfully.
273: * @author IT Mill Ltd.
274: * @version 3.1.1
275: * @since 3.0
276: */
277: public class SucceededEvent extends FinishedEvent {
278:
279: /**
280: * Serial generated by eclipse.
281: */
282: private static final long serialVersionUID = 3256445798169524023L;
283:
284: public SucceededEvent(Upload source, String filename,
285: String MIMEType, long length) {
286: super (source, filename, MIMEType, length);
287: }
288:
289: }
290:
291: /** Receives events when the uploads are ready.
292: * @author IT Mill Ltd.
293: * @version 3.1.1
294: * @since 3.0
295: */
296: public interface FinishedListener {
297:
298: /** Upload has finished.
299: * @param event Upload finished event.
300: */
301: public void uploadFinished(FinishedEvent event);
302: }
303:
304: /** Receives events when the uploads are finished, but unsuccessfull.
305: * @author IT Mill Ltd.
306: * @version 3.1.1
307: * @since 3.0
308: */
309: public interface FailedListener {
310:
311: /** Upload has finished unsuccessfully.
312: * @param event Upload failed event.
313: */
314: public void uploadFailed(FailedEvent event);
315: }
316:
317: /** Receives events when the uploads are successfully finished.
318: * @author IT Mill Ltd.
319: * @version 3.1.1
320: * @since 3.0
321: */
322: public interface SucceededListener {
323:
324: /** Upload successfull..
325: * @param event Upload successfull event.
326: */
327: public void uploadSucceeded(SucceededEvent event);
328: }
329:
330: /** Add upload received event listener
331: * @param listener Listener to be added.
332: */
333: public void addListener(FinishedListener listener) {
334: addListener(FinishedEvent.class, listener,
335: UPLOAD_FINISHED_METHOD);
336: }
337:
338: /** Remove upload received event listener
339: * @param listener Listener to be removed.
340: */
341: public void removeListener(FinishedListener listener) {
342: removeListener(FinishedEvent.class, listener,
343: UPLOAD_FINISHED_METHOD);
344: }
345:
346: /** Add upload interrupted event listener
347: * @param listener Listener to be added.
348: */
349: public void addListener(FailedListener listener) {
350: addListener(FailedEvent.class, listener, UPLOAD_FAILED_METHOD);
351: }
352:
353: /** Remove upload interrupted event listener
354: * @param listener Listener to be removed.
355: */
356: public void removeListener(FailedListener listener) {
357: removeListener(FinishedEvent.class, listener,
358: UPLOAD_FAILED_METHOD);
359: }
360:
361: /** Add upload success event listener
362: * @param listener Listener to be added.
363: */
364: public void addListener(SucceededListener listener) {
365: addListener(SucceededEvent.class, listener,
366: UPLOAD_SUCCEEDED_METHOD);
367: }
368:
369: /** Remove upload success event listener
370: * @param listener Listener to be removed.
371: */
372: public void removeListener(SucceededListener listener) {
373: removeListener(SucceededEvent.class, listener,
374: UPLOAD_SUCCEEDED_METHOD);
375: }
376:
377: /** Emit upload received event. */
378: protected void fireUploadReceived(String filename, String MIMEType,
379: long length) {
380: fireEvent(new Upload.FinishedEvent(this , filename, MIMEType,
381: length));
382: }
383:
384: /** Emit upload interrupted event. */
385: protected void fireUploadInterrupted(String filename,
386: String MIMEType, long length) {
387: fireEvent(new Upload.FailedEvent(this , filename, MIMEType,
388: length));
389: }
390:
391: /** Emit upload success event. */
392: protected void fireUploadSuccess(String filename, String MIMEType,
393: long length) {
394: fireEvent(new Upload.SucceededEvent(this , filename, MIMEType,
395: length));
396: }
397:
398: /** Returns the current receiver.
399: * @return Receiver
400: */
401: public Receiver getReceiver() {
402: return receiver;
403: }
404:
405: /** Sets the receiver.
406: * @param receiver The receiver to set
407: */
408: public void setReceiver(Receiver receiver) {
409: this .receiver = receiver;
410: }
411:
412: /**
413: * @see org.millstone.base.ui.Component.Focusable#focus()
414: */
415: public void focus() {
416: Window w = getWindow();
417: if (w != null) {
418: w.setFocusedComponent(this );
419: }
420: }
421:
422: /**
423: * @see org.millstone.base.ui.Component.Focusable#getTabIndex()
424: */
425: public int getTabIndex() {
426: return this .tabIndex;
427: }
428:
429: /**
430: * @see org.millstone.base.ui.Component.Focusable#setTabIndex(int)
431: */
432: public void setTabIndex(int tabIndex) {
433: this .tabIndex = tabIndex;
434: }
435:
436: /**
437: * @see org.millstone.base.ui.Component.Focusable#getFocusableId()
438: */
439: public long getFocusableId() {
440: return this.focusableId;
441: }
442:
443: }
|