View Javadoc

1   /*
2    * $Id: LibraryStructuralEdit.java,v 1.4 2005/06/01 17:38:38 jlerner Exp $
3    *
4    * Copyright (c) 1999-2004, BBN Technologies, LLC.
5    * All rights reserved.
6    * http://www.daml.org/legal/opensource/bbn_license.html
7    */
8    
9   package com.bbn.swede.core.libraries;
10  
11  import java.io.BufferedInputStream;
12  import java.io.BufferedOutputStream;
13  import java.io.File;
14  import java.io.FileInputStream;
15  import java.io.FileNotFoundException;
16  import java.io.FileOutputStream;
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.lang.reflect.InvocationTargetException;
20  import java.net.URL;
21  
22  import org.eclipse.core.resources.IFile;
23  import org.eclipse.core.runtime.CoreException;
24  import org.eclipse.core.runtime.IProgressMonitor;
25  import org.eclipse.core.runtime.IStatus;
26  import org.eclipse.core.runtime.MultiStatus;
27  import org.eclipse.core.runtime.Status;
28  import org.eclipse.core.runtime.SubProgressMonitor;
29  
30  import com.bbn.swede.core.OWLCore;
31  
32  /***
33   * <p>Represents the addition or deletion of a file from a library.  
34   * This class can also perform metadata updates for both library 
35   * entries and the library itself.</p>
36   * 
37   * <p>As defined in {@link com.bbn.swede.core.libraries.LibraryEdit}, 
38   * there are 4 possible types of edits, identified by the constants 
39   * in that class {@link LibraryEdit#ADDITION},
40   * {@link LibraryEdit#DELETION}, {@link LibraryEdit#REFRESH}, 
41   * and {@link LibraryEdit#CONFIGURATION}.  Additionally, the 
42   * modifier {@link LibraryEdit#LIBRARY_LEVEL} can be combined with 
43   * {@link LibraryEdit#CONFIGURATION} with a logical OR to set 
44   * library-level metadata.</p>
45   *
46   * <p>Depending on which type of operation is desired, different 
47   * constructors should be called, and different parameters to those 
48   * constructors are allowed to be <code>null</code>.</p>
49   * <ul>
50   *    <li>ADDITION - use {@link #LibraryStructuralEdit(IFile, String, int)},  
51   *       {@link #LibraryStructuralEdit(File, String, int)}, 
52   *       or {@link #LibraryStructuralEdit(URL, String, int)}, 
53   *       none of the arguments may be <code>null</code>.</li>
54   *    <li>DELETION - use {@link #LibraryStructuralEdit(IFile, String, int)},  
55   *       {@link #LibraryStructuralEdit(File, String, int)}, or 
56   *       {@link #LibraryStructuralEdit(URL, String, int)}, the first of the 
57   *       three arguments may be <code>null</code> regardless of which 
58   *       constructor.</li>
59   *    <li>REFRESH - use {@link #LibraryStructuralEdit(URL, String, int)}, 
60   *       none of the arguments may be <code>null</code>.</li>
61   *    <li>CONFIGURATION - use {@link #LibraryStructuralEdit(IConfiguration, int)},
62   *       none of the arguments may be <code>null</code>.</li>
63   *    <li>CONFIGURATION | LIBRARY_LEVEL - use 
64   *       {@link #LibraryStructuralEdit(IConfiguration, int)}, none of the 
65   *       arguments may be <code>null</code>.</li>
66   * </ul>
67   *  
68   *
69   * 
70   * 
71   * @author aperezlo
72   */
73  public class LibraryStructuralEdit
74  {
75     private URL _urlFile;
76     private IFile _ifileFile;
77     private File _fileFile;
78     
79     private String _name;
80     private int _type;
81  
82     private IConfiguration _configuration;
83     
84     /***
85      * Creates a library edit with a specified name and type.
86      * @param name The name
87      * @param type The type.  See {@link LibraryEdit} for edit type constants.
88      */
89     protected LibraryStructuralEdit(String name, int type)
90     {
91        _name = name;
92        _type = type;
93        _urlFile = null;
94        _ifileFile = null;
95        _fileFile = null;
96        _configuration = null;
97     }
98     
99     /***
100     * Creates a library edit for a URL within the library.  This constructor
101     * should be used to create edits of type <code>LibraryEdit.REFRESH</code>,
102     * <code>LibraryEdit.ADDITION</code>, or <code>LibraryEdit.DELETION</code>.
103     * @param file The source URL of the entry to edit
104     * @param name The name
105     * @param type The type.  See {@link LibraryEdit} for edit type constants.
106     */
107    public LibraryStructuralEdit(URL file, String name, int type)
108    {
109       this(name, type);
110       _urlFile = file;
111    }
112    /***
113     * Creates a library edit with a specified name and type.  This constructor
114     * should be used to create edits of type <code>LibraryEdit.ADDITION</code>
115     * and <code>LibraryEdit.DELETION</code>.
116     * @param file The file resource to edit
117     * @param name The name
118     * @param type The type.  See {@link LibraryEdit} for edit type constants.
119     */
120    public LibraryStructuralEdit(IFile file, String name, int type)
121    {
122       this(name, type);
123       _ifileFile = file;
124    }
125    /***
126     * Creates a library edit with a specified name and type.
127     * @param file The file to edit
128     * @param name The name
129     * @param type The type.  See {@link LibraryEdit} for edit type constants.
130     */
131    public LibraryStructuralEdit(File file, String name, int type)
132    {
133       this(name, type);
134       _fileFile = file;
135    }
136    
137    /***
138     * Creates a library edit for the specified configuration and type.  This
139     * constructor should be used for edits of type 
140     * <code>LibraryEdit.CONFIGURATION</code> and
141     * <code>LibraryEdit.CONFIGURATION | LibraryEdit.LIBRARY_LEVEL</code>.
142     * @param config The configuration
143     * @param type The type.  See {@link LibraryEdit} for edit type constants.
144     */
145    public LibraryStructuralEdit(IConfiguration config, int type)
146    {
147       this(config.getName(), type);
148       _configuration = config;
149    }
150    
151    /***
152     * Retrieves the type of this edit.
153     * @return the edit type
154     */
155    public int getType()
156    {
157       return _type;
158    }
159    
160    /***
161     * Retrieves the name of the resource to which this edit applies.
162     * @return the name of the resource
163     */
164    public String getName()
165    {
166       return _name;
167    }
168    
169    /***
170     * Performs a configuration operation, either on a library or a library
171     * entry. This operation supports cancelation.
172     * 
173     * @param ild the library in which the file to be configured lives, or the
174     *        library whose metadata should be changed
175     * @param progress a progress monitor to be informed of the progress of this
176     *        operation
177     * @return an IStatus object with code <code>IStatus.OK</code> if a success, 
178     *         and an error otherwise, or Status.CANCEL_STATUS if the operation 
179     *         was canceled
180     */
181    public IStatus configure(ILibraryDescriptor ild, IProgressMonitor progress)
182    {
183       MultiStatus toReturn = new MultiStatus(OWLCore.getID(), IStatus.OK, "Configuration succeeded", null);
184       ILibraryEntryDescriptor iled = null;
185       
186       progress.beginTask("Configuration...", 100);
187       if((_type & LibraryEdit.LIBRARY_LEVEL) == LibraryEdit.LIBRARY_LEVEL)
188       {
189          try
190          {
191             ild.getConfiguration().setProperties(_configuration.getProperties());
192             progress.worked(100);
193          }
194          catch (Exception e)
195          {
196             toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(), IStatus.OK,
197                "Unexpected error in library edit.", e));
198          }
199       }
200       else 
201       {
202          iled = ild.getDescriptorFor(_name);
203          if(iled != null)
204          {
205             try
206             {  
207                iled.getConfiguration().setProperties(_configuration.getProperties());
208                progress.worked(100);
209             }
210             catch(Exception e)
211             {
212                toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
213                   IStatus.OK, "Unexpected error in library edit.", e));
214             }
215          }
216          else
217          {
218             toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(), IStatus.OK,
219                "Could not find library entry '" + _name + "'.", null));
220          }
221       }
222       progress.done();
223       if(progress.isCanceled())
224       {
225          toReturn.add(Status.CANCEL_STATUS);
226       }
227       return toReturn;
228    }
229    
230    /***
231     * Performs an addition, deletion or refresh operation on a library entry.
232     * This operation supports cancelation.
233     * 
234     * @param directory The directory in which the operation should be performed
235     * @param progress a progress monitor to be informed of the progress of this
236     *        operation
237     * @return an IStatus object with code IStatus.OK if a success, and an error
238     *         otherwise, or Status.CANCEL_STATUS if the operation was canceled
239     */
240    public IStatus perform(File directory, IProgressMonitor progress)
241    {
242       MultiStatus toReturn = new MultiStatus(OWLCore.getID(), IStatus.OK, "Edit succeeded", null);
243       File workFile = null;
244       
245       String editString = (_type == LibraryEdit.DELETION ? "Deleting " 
246          :  _type == LibraryEdit.ADDITION ? "Adding " 
247          :  _type == LibraryEdit.REFRESH  ? "Refreshing " : "");
248       
249       progress.beginTask("Performing edit: (" + editString + "'" + _name + "'...)", 100);
250       workFile = new File(directory, _name);
251       DownloadFileOperation dfo;
252       switch(_type)
253       {
254          case LibraryEdit.DELETION:
255             if(!workFile.delete())
256             {
257                toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
258                   IStatus.OK, "Could not delete '" + workFile.toString() + "'",
259                   null));
260             }
261             progress.worked(100);
262             break;
263          case LibraryEdit.REFRESH:
264             dfo = null;
265             if(_urlFile != null)
266             {
267                dfo = new DownloadFileOperation(_urlFile, _name, true);
268                try
269                {
270                   dfo.run(new SubProgressMonitor(progress, 80));
271                }
272                catch (InvocationTargetException e)
273                {
274                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
275                      IStatus.OK, "Could not download file '"
276                         + _urlFile.toString() + "'", e));
277                }
278                catch (InterruptedException e)
279                {
280                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
281                      IStatus.OK, "Could not download file '"
282                         + _urlFile.toString() + "': Interrupted", e));
283                }
284             
285                if(dfo.getExceptions().size() == 0 && !progress.isCanceled())
286                {
287                   workFile.delete();
288                   try
289                   {
290                      copy(new FileInputStream(dfo.getFile()), workFile, new SubProgressMonitor(progress, 20));
291                   }
292                   catch (FileNotFoundException e1)
293                   {
294                      toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
295                         IStatus.OK, "Could not download file '"
296                            + _urlFile.toString() + "': File not found", e1));
297                   }
298                }
299             }
300             break;
301          case LibraryEdit.ADDITION:
302             if(_fileFile != null)
303             {
304                try
305                {
306                   copy(new FileInputStream(_fileFile), workFile, new SubProgressMonitor(progress, 100));
307                }
308                catch (FileNotFoundException e)
309                {
310                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
311                      IStatus.OK, "Could not copy file '" + _fileFile.toString()
312                         + "': File not found", e));
313                }
314             } 
315             else if(_urlFile != null)
316             {
317                dfo = new DownloadFileOperation(_urlFile);
318                try
319                {
320                   dfo.run(new SubProgressMonitor(progress, 80));
321                }
322                catch (InvocationTargetException e)
323                {
324                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
325                      IStatus.OK, "Could not download file '"
326                         + _urlFile.toString() + "'", e));
327                }
328                catch (InterruptedException e)
329                {
330                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
331                      IStatus.OK, "Could not download file '"
332                         + _urlFile.toString() + "': Interrupted", e));
333                }
334                if(dfo.getExceptions().size() == 0 && !progress.isCanceled())
335                {
336                   try
337                   {
338                      copy(new FileInputStream(dfo.getFile()), workFile, new SubProgressMonitor(progress, 20));
339                   }
340                   catch (FileNotFoundException e1)
341                   {
342                      toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
343                         IStatus.OK, "Could not add file '"
344                            + _urlFile.toString() + "': File not found", e1));
345                   }
346                }
347             }
348             else if(_ifileFile != null)
349             {
350                try
351                {
352                   copy(_ifileFile.getContents(), workFile, new SubProgressMonitor(progress, 100));
353                }
354                catch (CoreException e)
355                {
356                   toReturn.add(new Status(IStatus.ERROR, OWLCore.getID(),
357                      IStatus.OK, "Could not add file '" + _urlFile.toString()
358                         + "'", e));
359                }
360             }
361             break;
362          default:
363             break;
364       }
365 
366       progress.done();
367       if(progress.isCanceled())
368       {
369          toReturn.add(Status.CANCEL_STATUS);
370       }
371       return toReturn;
372    }
373    
374    private void copy(InputStream source, File destination, IProgressMonitor progress)
375    {
376       final int iChunkSize = 2048;
377       int length = iChunkSize;
378       byte[] buffer = new byte[iChunkSize];
379       BufferedInputStream in = null;
380       BufferedOutputStream out = null;
381       double contentLength = 0.0;
382       
383       try
384       {
385          in = new BufferedInputStream(source);
386          out = new BufferedOutputStream(new FileOutputStream(destination));
387          contentLength = in.available();
388          int bytesDownloaded = 0;
389          int totalBytesDownloaded = 0;
390          
391          while(length > -1 && !progress.isCanceled())
392          {
393             length = iChunkSize;
394             length = in.read(buffer, 0, length);
395             if(length > -1)
396             {
397                out.write(buffer, 0, length);
398                out.flush();
399             }
400             bytesDownloaded += length;
401             if(bytesDownloaded > (contentLength / 100))
402             {
403                progress.worked((int) Math.floor(bytesDownloaded / (contentLength / 100)));
404                bytesDownloaded = 0;
405                length = iChunkSize;
406             }
407          }
408       }
409       catch (FileNotFoundException e)
410       {
411          e.printStackTrace();
412       }
413       catch (IOException e)
414       {
415          e.printStackTrace();
416       }
417       finally
418       {
419          try
420          {
421             out.flush();
422             out.close();
423             in.close();
424          }
425          catch (IOException e1)
426          {
427             e1.printStackTrace();
428          }
429          finally
430          {
431             progress.done();
432          }
433       }
434    }
435    
436    
437 }