plugins/base2/net.sf.basedb.examples/trunk/src/net/sf/basedb/exampleplugins/ExampleImporter.java

Code
Comments
Other
Rev Date Author Line
647 11 Apr 08 nicklas 1 /*
647 11 Apr 08 nicklas 2   Copyright (C) 2006, 2007 Nicklas Nordborg
647 11 Apr 08 nicklas 3
647 11 Apr 08 nicklas 4   This file is part of BASE - BioArray Software Environment.
647 11 Apr 08 nicklas 5   Available at http://base.thep.lu.se/
647 11 Apr 08 nicklas 6
647 11 Apr 08 nicklas 7   BASE is free software; you can redistribute it and/or
647 11 Apr 08 nicklas 8   modify it under the terms of the GNU General Public License
647 11 Apr 08 nicklas 9   as published by the Free Software Foundation; either version 2
647 11 Apr 08 nicklas 10   of the License, or (at your option) any later version.
647 11 Apr 08 nicklas 11
647 11 Apr 08 nicklas 12   BASE is distributed in the hope that it will be useful,
647 11 Apr 08 nicklas 13   but WITHOUT ANY WARRANTY; without even the implied warranty of
647 11 Apr 08 nicklas 14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
647 11 Apr 08 nicklas 15   GNU General Public License for more details.
647 11 Apr 08 nicklas 16
647 11 Apr 08 nicklas 17   You should have received a copy of the GNU General Public License
647 11 Apr 08 nicklas 18   along with this program; if not, write to the Free Software
647 11 Apr 08 nicklas 19   Foundation, Inc., 59 Temple Place - Suite 330,
647 11 Apr 08 nicklas 20   Boston, MA  02111-1307, USA.
647 11 Apr 08 nicklas 21
647 11 Apr 08 nicklas 22 */
647 11 Apr 08 nicklas 23 package net.sf.basedb.exampleplugins;
647 11 Apr 08 nicklas 24
647 11 Apr 08 nicklas 25 import net.sf.basedb.core.BooleanParameterType;
647 11 Apr 08 nicklas 26 import net.sf.basedb.core.BaseException;
647 11 Apr 08 nicklas 27 import net.sf.basedb.core.DbControl;
647 11 Apr 08 nicklas 28 import net.sf.basedb.core.Item;
647 11 Apr 08 nicklas 29 import net.sf.basedb.core.Job;
647 11 Apr 08 nicklas 30 import net.sf.basedb.core.File;
647 11 Apr 08 nicklas 31 import net.sf.basedb.core.FileParameterType;
647 11 Apr 08 nicklas 32 import net.sf.basedb.core.PluginParameter;
647 11 Apr 08 nicklas 33 import net.sf.basedb.core.ProgressReporter;
647 11 Apr 08 nicklas 34 import net.sf.basedb.core.RequestInformation;
647 11 Apr 08 nicklas 35
647 11 Apr 08 nicklas 36 import net.sf.basedb.core.plugin.About;
647 11 Apr 08 nicklas 37 import net.sf.basedb.core.plugin.AboutImpl;
647 11 Apr 08 nicklas 38 import net.sf.basedb.core.plugin.AbstractPlugin;
647 11 Apr 08 nicklas 39 import net.sf.basedb.core.plugin.AutoDetectingImporter;
647 11 Apr 08 nicklas 40 import net.sf.basedb.core.plugin.InteractivePlugin;
647 11 Apr 08 nicklas 41 import net.sf.basedb.core.plugin.GuiContext;
647 11 Apr 08 nicklas 42 import net.sf.basedb.core.plugin.Plugin;
647 11 Apr 08 nicklas 43 import net.sf.basedb.core.plugin.Request;
647 11 Apr 08 nicklas 44 import net.sf.basedb.core.plugin.Response;
647 11 Apr 08 nicklas 45 import net.sf.basedb.core.signal.SignalHandler;
647 11 Apr 08 nicklas 46 import net.sf.basedb.core.signal.SignalTarget;
647 11 Apr 08 nicklas 47 import net.sf.basedb.core.signal.ThreadSignalHandler;
647 11 Apr 08 nicklas 48
647 11 Apr 08 nicklas 49 import java.io.InputStream;
647 11 Apr 08 nicklas 50 import java.util.ArrayList;
647 11 Apr 08 nicklas 51 import java.util.Arrays;
647 11 Apr 08 nicklas 52 import java.util.Collections;
647 11 Apr 08 nicklas 53 import java.util.List;
647 11 Apr 08 nicklas 54 import java.util.Set;
647 11 Apr 08 nicklas 55
647 11 Apr 08 nicklas 56
647 11 Apr 08 nicklas 57 /**
647 11 Apr 08 nicklas 58   An example plugin that pretends to import samples. It can't be configured,
647 11 Apr 08 nicklas 59   but will ask for a file to import from and if existing samples should be updated 
647 11 Apr 08 nicklas 60   or not. It won't actually import any samples, but will report that a few samples
647 11 Apr 08 nicklas 61   has been imported.
647 11 Apr 08 nicklas 62   
647 11 Apr 08 nicklas 63   @base.modified $Date$
647 11 Apr 08 nicklas 64   @author Nicklas
647 11 Apr 08 nicklas 65   @version 2.0
647 11 Apr 08 nicklas 66 */
647 11 Apr 08 nicklas 67 public class ExampleImporter 
647 11 Apr 08 nicklas 68   extends AbstractPlugin
647 11 Apr 08 nicklas 69   implements InteractivePlugin, AutoDetectingImporter, SignalTarget
647 11 Apr 08 nicklas 70 {
647 11 Apr 08 nicklas 71
647 11 Apr 08 nicklas 72   private static final About about = 
647 11 Apr 08 nicklas 73     new AboutImpl
647 11 Apr 08 nicklas 74     (
647 11 Apr 08 nicklas 75       "Example importer",
647 11 Apr 08 nicklas 76       "An example plugin that pretends to import samples. It can't be configured, " +
647 11 Apr 08 nicklas 77       "but will ask for a file to import from and if existing samples should be updated " +
647 11 Apr 08 nicklas 78       "or not. It won't actually import any samples, but will report that a few samples " +
647 11 Apr 08 nicklas 79       "has been imported.",
1292 24 Feb 11 nicklas 80       "2.17",
647 11 Apr 08 nicklas 81       "2006, Base 2 development team",
647 11 Apr 08 nicklas 82       null,
647 11 Apr 08 nicklas 83       null,
647 11 Apr 08 nicklas 84       "http://base.thep.lu.se"
647 11 Apr 08 nicklas 85     );
647 11 Apr 08 nicklas 86
647 11 Apr 08 nicklas 87   private static final Set<GuiContext> guiContexts = Collections.singleton(
647 11 Apr 08 nicklas 88     new GuiContext(Item.SAMPLE, GuiContext.Type.LIST)
647 11 Apr 08 nicklas 89   );
647 11 Apr 08 nicklas 90   
647 11 Apr 08 nicklas 91   // Job configuration is created by getConfigureJob()
647 11 Apr 08 nicklas 92   private RequestInformation configureJob;
647 11 Apr 08 nicklas 93   
647 11 Apr 08 nicklas 94   // Parameter that asks for the file to import from
647 11 Apr 08 nicklas 95   private PluginParameter<File> fileParameter;
647 11 Apr 08 nicklas 96   
647 11 Apr 08 nicklas 97   // Parameter that asks if existing items should be updated or not
647 11 Apr 08 nicklas 98   private PluginParameter<Boolean> updateExistingParameter;
647 11 Apr 08 nicklas 99   
647 11 Apr 08 nicklas 100   // 
647 11 Apr 08 nicklas 101   private DbControl dc;
647 11 Apr 08 nicklas 102   
647 11 Apr 08 nicklas 103   // So we can react to ABORT requests
647 11 Apr 08 nicklas 104   private ThreadSignalHandler signalHandler;
647 11 Apr 08 nicklas 105   
647 11 Apr 08 nicklas 106   /**
647 11 Apr 08 nicklas 107     Create a new example importer.
647 11 Apr 08 nicklas 108   */
647 11 Apr 08 nicklas 109   public ExampleImporter()
647 11 Apr 08 nicklas 110   {}
647 11 Apr 08 nicklas 111   
647 11 Apr 08 nicklas 112   /*
647 11 Apr 08 nicklas 113     From the Plugin interface
647 11 Apr 08 nicklas 114     -------------------------------------------
647 11 Apr 08 nicklas 115   */
1292 24 Feb 11 nicklas 116   @Override
647 11 Apr 08 nicklas 117   public About getAbout()
647 11 Apr 08 nicklas 118   {
647 11 Apr 08 nicklas 119     return about;
647 11 Apr 08 nicklas 120   }
1292 24 Feb 11 nicklas 121   @Override
647 11 Apr 08 nicklas 122   public Plugin.MainType getMainType()
647 11 Apr 08 nicklas 123   {
647 11 Apr 08 nicklas 124     return Plugin.MainType.IMPORT;
647 11 Apr 08 nicklas 125   }
1292 24 Feb 11 nicklas 126   @Override
647 11 Apr 08 nicklas 127   public boolean supportsConfigurations()
647 11 Apr 08 nicklas 128   {
647 11 Apr 08 nicklas 129     return false;
647 11 Apr 08 nicklas 130   }
1292 24 Feb 11 nicklas 131   @Override
647 11 Apr 08 nicklas 132   public boolean requiresConfiguration()
647 11 Apr 08 nicklas 133   {
647 11 Apr 08 nicklas 134     return false;
647 11 Apr 08 nicklas 135   }
1292 24 Feb 11 nicklas 136   @Override
647 11 Apr 08 nicklas 137   public void run(Request request, Response response, ProgressReporter progress)
647 11 Apr 08 nicklas 138   {
647 11 Apr 08 nicklas 139     // Ensure that the ABORT signal gets sent to this thread
647 11 Apr 08 nicklas 140     if (signalHandler != null) signalHandler.setWorkerThread(null);
647 11 Apr 08 nicklas 141     
647 11 Apr 08 nicklas 142     // Open a connection to the database
647 11 Apr 08 nicklas 143     // sc is set by init() method
647 11 Apr 08 nicklas 144     DbControl dc = sc.newDbControl();
647 11 Apr 08 nicklas 145     try
647 11 Apr 08 nicklas 146     {
647 11 Apr 08 nicklas 147       // Get the parameters from the job configuration
647 11 Apr 08 nicklas 148       boolean updateExisting = (Boolean)job.getValue("updateExisting");
647 11 Apr 08 nicklas 149       File f = (File)job.getValue("file");
647 11 Apr 08 nicklas 150       
647 11 Apr 08 nicklas 151       // Open the file an import it
647 11 Apr 08 nicklas 152       f = File.getById(dc, f.getId());
647 11 Apr 08 nicklas 153       InputStream in = f.getDownloadStream(0);
647 11 Apr 08 nicklas 154       doImport(in, progress);
647 11 Apr 08 nicklas 155       in.close();
647 11 Apr 08 nicklas 156       
647 11 Apr 08 nicklas 157       // Commit the work
647 11 Apr 08 nicklas 158       dc.commit();
647 11 Apr 08 nicklas 159       response.setDone("Plugin ended successfully");
647 11 Apr 08 nicklas 160     }
647 11 Apr 08 nicklas 161     catch (Throwable t)
647 11 Apr 08 nicklas 162     {
647 11 Apr 08 nicklas 163       // All exceptions must be catched and sent back 
647 11 Apr 08 nicklas 164       // using the response object
647 11 Apr 08 nicklas 165       response.setError(t.getMessage(), Arrays.asList(t));
647 11 Apr 08 nicklas 166     }
647 11 Apr 08 nicklas 167     finally
647 11 Apr 08 nicklas 168     {
647 11 Apr 08 nicklas 169       // IMPORTANT!!! Make sure opened connections are closed
647 11 Apr 08 nicklas 170       if (dc != null) dc.close();
647 11 Apr 08 nicklas 171     }
647 11 Apr 08 nicklas 172   }
647 11 Apr 08 nicklas 173   // -------------------------------------------
647 11 Apr 08 nicklas 174   
647 11 Apr 08 nicklas 175   /*
647 11 Apr 08 nicklas 176     From the InteractivePlugin interface
647 11 Apr 08 nicklas 177     -------------------------------------------
647 11 Apr 08 nicklas 178   */
647 11 Apr 08 nicklas 179   /**
647 11 Apr 08 nicklas 180     Return a set containing the context [SAMPLE, LIST].
647 11 Apr 08 nicklas 181   */
1292 24 Feb 11 nicklas 182   @Override
647 11 Apr 08 nicklas 183   public Set<GuiContext> getGuiContexts()
647 11 Apr 08 nicklas 184   {
647 11 Apr 08 nicklas 185     return guiContexts;
647 11 Apr 08 nicklas 186   }
647 11 Apr 08 nicklas 187   /**
647 11 Apr 08 nicklas 188     Always null, we are not dealing with individual items.
647 11 Apr 08 nicklas 189   */
1292 24 Feb 11 nicklas 190   @Override
647 11 Apr 08 nicklas 191   public String isInContext(GuiContext context, Object item)
647 11 Apr 08 nicklas 192   {
647 11 Apr 08 nicklas 193     return null;
647 11 Apr 08 nicklas 194   }
647 11 Apr 08 nicklas 195   /**
647 11 Apr 08 nicklas 196     The {@link Request#COMMAND_CONFIGURE_PLUGIN} command will not ask
647 11 Apr 08 nicklas 197     for any parameters.
647 11 Apr 08 nicklas 198     <p>
647 11 Apr 08 nicklas 199     The {@link Request#COMMAND_CONFIGURE_JOB} command will ask for
647 11 Apr 08 nicklas 200     a file and if existing samples should be updated or ignored.
647 11 Apr 08 nicklas 201   */
1292 24 Feb 11 nicklas 202   @Override
647 11 Apr 08 nicklas 203   public RequestInformation getRequestInformation(GuiContext context, String command)
647 11 Apr 08 nicklas 204     throws BaseException
647 11 Apr 08 nicklas 205   {
647 11 Apr 08 nicklas 206     RequestInformation requestInformation = null;
647 11 Apr 08 nicklas 207     if (command.equals(Request.COMMAND_CONFIGURE_JOB))
647 11 Apr 08 nicklas 208     {
647 11 Apr 08 nicklas 209       requestInformation = getConfigureJob(context);
647 11 Apr 08 nicklas 210     }
647 11 Apr 08 nicklas 211     return requestInformation;
647 11 Apr 08 nicklas 212   }
647 11 Apr 08 nicklas 213   /**
647 11 Apr 08 nicklas 214     Store configuration settings for {@link Request#COMMAND_CONFIGURE_PLUGIN} and
647 11 Apr 08 nicklas 215     {@link Request#COMMAND_CONFIGURE_JOB}.
647 11 Apr 08 nicklas 216   */
1292 24 Feb 11 nicklas 217   @Override
647 11 Apr 08 nicklas 218   public void configure(GuiContext context, Request request, Response response)
647 11 Apr 08 nicklas 219   {
647 11 Apr 08 nicklas 220     String command = request.getCommand();
647 11 Apr 08 nicklas 221     try
647 11 Apr 08 nicklas 222     {
647 11 Apr 08 nicklas 223       if (command.equals(Request.COMMAND_CONFIGURE_JOB))
647 11 Apr 08 nicklas 224       {
647 11 Apr 08 nicklas 225         List<Throwable> errors = 
647 11 Apr 08 nicklas 226           validateRequestParameters(getConfigureJob(context).getParameters(), request);
647 11 Apr 08 nicklas 227         if (errors != null)
647 11 Apr 08 nicklas 228         {
647 11 Apr 08 nicklas 229           response.setError(errors.size()+" invalid parameter(s) were found in the request", errors);
647 11 Apr 08 nicklas 230           return;
647 11 Apr 08 nicklas 231         }
647 11 Apr 08 nicklas 232
647 11 Apr 08 nicklas 233         storeValue(job, request, fileParameter);
647 11 Apr 08 nicklas 234         storeValue(job, request, updateExistingParameter);
1292 24 Feb 11 nicklas 235         File importFile = (File)job.getValue(fileParameter.getName());
1292 24 Feb 11 nicklas 236         response.setSuggestedJobName("Import samples from '" + importFile.getName() + "'");
647 11 Apr 08 nicklas 237         response.setDone("Job configuration complete", Job.ExecutionTime.SHORT);
647 11 Apr 08 nicklas 238         // TODO - maybe check file size to make a better estimate
647 11 Apr 08 nicklas 239       }
647 11 Apr 08 nicklas 240     }
647 11 Apr 08 nicklas 241     catch (Throwable ex)
647 11 Apr 08 nicklas 242     {
647 11 Apr 08 nicklas 243       response.setError(ex.getMessage(), Arrays.asList(ex));
647 11 Apr 08 nicklas 244     }
647 11 Apr 08 nicklas 245   }
647 11 Apr 08 nicklas 246   // -------------------------------------------
647 11 Apr 08 nicklas 247
647 11 Apr 08 nicklas 248
647 11 Apr 08 nicklas 249   /*
647 11 Apr 08 nicklas 250     From the AutoDetectingImporter interface
647 11 Apr 08 nicklas 251     -------------------------------------------
647 11 Apr 08 nicklas 252   */
647 11 Apr 08 nicklas 253   /**
647 11 Apr 08 nicklas 254     Always true, since we accept all files.
647 11 Apr 08 nicklas 255   */
1292 24 Feb 11 nicklas 256   @Override
647 11 Apr 08 nicklas 257   public boolean isImportable(InputStream in) 
647 11 Apr 08 nicklas 258     throws BaseException
647 11 Apr 08 nicklas 259   {
647 11 Apr 08 nicklas 260     return true;
647 11 Apr 08 nicklas 261   }
647 11 Apr 08 nicklas 262   /**
647 11 Apr 08 nicklas 263     We don't do anything in this method.
647 11 Apr 08 nicklas 264   */
1292 24 Feb 11 nicklas 265   @Override
647 11 Apr 08 nicklas 266   public void doImport(InputStream in, ProgressReporter progress) 
647 11 Apr 08 nicklas 267     throws BaseException
647 11 Apr 08 nicklas 268   {
647 11 Apr 08 nicklas 269     // Check if the ABORT signal has been sent
1292 24 Feb 11 nicklas 270     ThreadSignalHandler.checkInterrupted();
647 11 Apr 08 nicklas 271     /*
647 11 Apr 08 nicklas 272       Pseudo code:
647 11 Apr 08 nicklas 273       Parse input stream, for each found sample:
1292 24 Feb 11 nicklas 274       ThreadSignalHandler.checkInterrupted();  // Do this as the first thing in a loop
647 11 Apr 08 nicklas 275       String name = ...
647 11 Apr 08 nicklas 276       String externalId = ...
647 11 Apr 08 nicklas 277       boolean isNew = false;
647 11 Apr 08 nicklas 278       Sample s = getByExternalId(externalId);
647 11 Apr 08 nicklas 279       if (s == null)
647 11 Apr 08 nicklas 280       {
647 11 Apr 08 nicklas 281         s = Sample.getNew(dc);
1292 24 Feb 11 nicklas 282         s.setName(name) // and other properites
647 11 Apr 08 nicklas 283         dc.saveItem(s);
647 11 Apr 08 nicklas 284         isNew = true;
647 11 Apr 08 nicklas 285       }
647 11 Apr 08 nicklas 286       if (updateExisting || isNew)
647 11 Apr 08 nicklas 287       {
647 11 Apr 08 nicklas 288         s.setName(name);
647 11 Apr 08 nicklas 289         s.setExternalId(externalId);
647 11 Apr 08 nicklas 290         ...
647 11 Apr 08 nicklas 291       }
647 11 Apr 08 nicklas 292     */
647 11 Apr 08 nicklas 293   }
647 11 Apr 08 nicklas 294   // -------------------------------------------
647 11 Apr 08 nicklas 295   /*
647 11 Apr 08 nicklas 296     From the SignalTarget interface
647 11 Apr 08 nicklas 297     -------------------------------------------
647 11 Apr 08 nicklas 298   */
1292 24 Feb 11 nicklas 299   @Override
647 11 Apr 08 nicklas 300   public SignalHandler getSignalHandler()
647 11 Apr 08 nicklas 301   {
647 11 Apr 08 nicklas 302     signalHandler = new ThreadSignalHandler();
647 11 Apr 08 nicklas 303     return signalHandler;
647 11 Apr 08 nicklas 304   }
647 11 Apr 08 nicklas 305   // -------------------------------------------
647 11 Apr 08 nicklas 306
647 11 Apr 08 nicklas 307   private RequestInformation getConfigureJob(GuiContext context)
647 11 Apr 08 nicklas 308   {
647 11 Apr 08 nicklas 309     if (configureJob == null)
647 11 Apr 08 nicklas 310     {
647 11 Apr 08 nicklas 311       // Create file parameter
647 11 Apr 08 nicklas 312       fileParameter = new PluginParameter<File>(
647 11 Apr 08 nicklas 313         "file",
647 11 Apr 08 nicklas 314         "File",
647 11 Apr 08 nicklas 315         "The file to import the data from",
647 11 Apr 08 nicklas 316         new FileParameterType(null, true, 1)
647 11 Apr 08 nicklas 317       );
647 11 Apr 08 nicklas 318       
647 11 Apr 08 nicklas 319       // Create update existing parameter
647 11 Apr 08 nicklas 320       updateExistingParameter = new PluginParameter<Boolean>(
647 11 Apr 08 nicklas 321         "updateExisting",
647 11 Apr 08 nicklas 322         "Update existing samples",
647 11 Apr 08 nicklas 323         "If this option is selected, already existing samples will be updated with the information "+
647 11 Apr 08 nicklas 324         "in the file. If this option isn't selected existing samples are left untouched.",
647 11 Apr 08 nicklas 325         new BooleanParameterType(false, true)
647 11 Apr 08 nicklas 326       );
647 11 Apr 08 nicklas 327       
647 11 Apr 08 nicklas 328       // Create parameter list and request informaion
647 11 Apr 08 nicklas 329       List<PluginParameter<?>> parameters = new ArrayList<PluginParameter<?>>();
647 11 Apr 08 nicklas 330       parameters.add(fileParameter);
647 11 Apr 08 nicklas 331       parameters.add(updateExistingParameter);
647 11 Apr 08 nicklas 332       
647 11 Apr 08 nicklas 333       configureJob = new RequestInformation
647 11 Apr 08 nicklas 334       (
647 11 Apr 08 nicklas 335         Request.COMMAND_CONFIGURE_JOB,
647 11 Apr 08 nicklas 336         "Select a file to import samples from",
647 11 Apr 08 nicklas 337         "This is an example plugin, it will accept any file but won't import any samples.",
647 11 Apr 08 nicklas 338         parameters
647 11 Apr 08 nicklas 339       );
647 11 Apr 08 nicklas 340     }
647 11 Apr 08 nicklas 341     return configureJob;
647 11 Apr 08 nicklas 342   }
647 11 Apr 08 nicklas 343
647 11 Apr 08 nicklas 344 }