diff m-toolbox/classes/@ltpda_uo/update.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children 8be9deffe989
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/@ltpda_uo/update.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,334 @@
+% UPDATE Updates the given object in an LTPDA repository
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: Update an LTPDA object in the repository with the given
+% replacement object. The replacement object should be of the same kind of
+% the object that will be updated.
+%
+% CALL:        update(OBJ, ID, PL)
+%
+% INPUTS:      OBJ   - replacement object
+%              ID    - repository ID of the object to update
+%              PL    - plist whih submission and repository informations
+%
+% <a href="matlab:utils.helper.displayMethodInfo('ltpda_uo', 'update')">Parameters Description</a>
+%
+% VERSION:     $Id: update.m,v 1.45 2011/11/18 08:09:45 mauro Exp $
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function varargout = update(varargin)
+  
+  % check if this is a call for parameters
+  if utils.helper.isinfocall(varargin{:})
+    varargout{1} = getInfo(varargin{3});
+    return
+  end
+  
+  import utils.const.*
+  utils.helper.msg(msg.PROC3, 'running %s/%s', mfilename('class'), mfilename);
+  
+  % collect all AOs
+  obj   = utils.helper.collect_objects(varargin(:), '');
+  objid = utils.helper.collect_objects(varargin(:), 'double');
+  pls   = utils.helper.collect_objects(varargin(:), 'plist');
+  sinfo = utils.helper.collect_objects(varargin(:), 'struct');
+  
+  % if the object to update is a plist it is possible we collected it along
+  % the plist used to supply parameter to the update routine
+  if isa(obj, 'plist')
+    % identify plists which are only used for the submission process
+    mask = false(numel(obj), 1);
+    for ii = 1:numel(obj)
+      if ~utils.helper.isSubmissionPlist(obj(ii))
+        mask(ii) = true;
+      end
+    end
+    obj = obj(mask);
+    % keep all the other as parameters plist
+    pls = [ pls combine(pls(~mask)) ];
+  end
+  
+  if isempty(obj)
+    error('### please input an LTPDA user object as the first argument');
+  end
+  
+  if isempty(objid)
+    error('### please provide the repository ID for the object which should be updated');
+  end
+  
+  % combine plists
+  dpl = getDefaultPlist();
+  pls = combine(pls, dpl.pset('HOSTNAME', ''));
+  
+  % for backwards compatibility convert any user supplied sinfo-structure into a plist
+  pls = ltpda_uo.convertSinfo2Plist(pls, sinfo);
+  
+  % check if the user wants to update the submission informations
+  if changeSinfo(pls)
+    sinfo = ltpda_uo.submitDialog(pls);
+    if isempty(sinfo)
+      [varargout{1}, varargout{2}] = userCanceled();
+      return
+    end
+  else
+    sinfo = [];
+  end
+  
+  % user supplied connection
+  conn = find(pls, 'conn');
+  
+  if isempty(conn)
+    % obtain a connection from the connection manager
+    rm = LTPDARepositoryManager();
+    connections = rm.findConnections(pls);
+    if isempty(connections)
+      % no connection found. create a new one
+      conn = rm.newConnection(pls);
+      if isempty(conn)
+        [varargout{1}, varargout{2}] = userCanceled();
+        return
+      end
+    elseif numel(connections) == 1 && ~utils.prog.yes2true(pls.find('use selector'))
+      % found only one connection and we are not forcing the use of the selector
+      conn = connections(1);
+    else
+      % make the user select the desired database connection
+      conn = rm.manager.selectConnection([]);
+      if isempty(conn)
+        [varargout{1}, varargout{2}] = userCanceled();
+        return
+      end
+    end
+  end
+  
+  % avoid to ask for a password if one was specified in the plist
+  if isjava(conn) && ~conn.isConnected()
+    passwd = pls.find('password');
+    if ~isempty(passwd)
+      conn.setPassword(passwd);
+    end
+  end
+  
+  % connect to the database
+  if isempty(conn.openConnection())
+    error('### unable to connect to the database')
+  end
+  
+  try
+    % lock connection to avoid expire during processing
+    conn.setLocked(true);
+    
+    % look-up user id
+    userid   = utils.jmysql.getUserID(conn);
+    username = conn.getUsername();
+    
+    utils.helper.msg(msg.PROC1, 'got user id %d for user: %s', userid, char(username));
+    if userid < 1 || isnan(userid)  || strcmp(userid, 'No Data') || ischar(userid)
+      error('### Unknown username.');
+    end
+    
+    % author of the data: let's take the username
+    author = username;
+    
+    % date for the transaction.transdata and objmeta.submitted columns as UTC time string
+    t     = time();
+    tdate = format(t, 'yyyy-mm-dd HH:MM:SS', 'UTC');
+    
+    % machine details
+    prov = provenance();
+    
+    utils.helper.msg(msg.IMPORTANT, 'submitting to %s@%s:%s', ...
+      char(conn.getUsername), char(conn.getHostname), char(conn.getDatabase));
+    
+    % obtain the underlying connection
+    c = conn.getConn();
+    
+    % start a transaction. either we submitt all objects or we roll back all changes
+    c.setAutoCommit(false);
+    
+    utils.helper.msg(msg.PROC1, 'updating object %d with: %s / %s', objid, class(obj), obj.name);
+    
+    % format object creation time as UTC time string
+    if isa(obj, 'plist')
+      % plist-objects stores creatins time as milli secs since the epoch
+      created = time().format('yyyy-mm-dd HH:MM:SS', 'UTC');
+    else
+      created = obj.created.format('yyyy-mm-dd HH:MM:SS', 'UTC');
+    end
+    
+    % Set the UUID if it is empty. This should only happen for PLIST objects
+    if isempty(obj.UUID)
+      obj.UUID = char(java.util.UUID.randomUUID);
+    end
+    
+    % create an XML representaion of the object
+    if utils.prog.yes2true(pls.find('binary'));
+      utils.helper.msg(msg.PROC2, 'binary submit');
+      otxt = ['binary submit ' datestr(now)];
+    else
+      utils.helper.msg(msg.PROC2, 'xml submit');
+      otxt = utils.prog.obj2xml(obj);
+    end
+    
+    % create an MD5 hash of the xml representation
+    md5hash = utils.prog.hash(otxt, 'MD5');
+    
+    % create a binary representaion of the object
+    bobj = utils.prog.obj2binary(obj);
+    if isempty(bobj)
+      error('### failed to obtain a binary representation');
+    end
+    
+    % update object in objs table
+    stmt = c.prepareStatement(...
+      'UPDATE objs SET xml=?, hash=?, uuid=? WHERE id=?');
+    stmt.setObject(1, otxt);
+    stmt.setObject(2, char(md5hash));
+    stmt.setObject(3, obj.UUID);
+    stmt.setObject(4, objid);
+    stmt.executeUpdate();
+    stmt.close();
+    
+    % update binary
+    stmt = c.prepareStatement(...
+      'UPDATE bobjs SET mat=? WHERE obj_id=?');
+    stmt.setObject(1, bobj);
+    stmt.setObject(2, objid);
+    stmt.executeUpdate();
+    stmt.close();
+    
+    % update object meta data
+    if isempty(sinfo)
+      stmt = c.prepareStatement(...
+        [ 'UPDATE objmeta SET obj_type=?, name=?, created=?, version=?, ' ...
+        'ip=?, hostname=?, os=?, submitted=?, author=? WHERE obj_id=?' ]);
+      stmt.setObject( 1, java.lang.String(class(obj)));
+      stmt.setObject( 2, java.lang.String(obj.name));
+      stmt.setObject( 3, java.lang.String(created));
+      stmt.setObject( 4, java.lang.String(getappdata(0, 'ltpda_version')));
+      stmt.setObject( 5, java.lang.String(prov.ip));
+      stmt.setObject( 6, java.lang.String(prov.hostname));
+      stmt.setObject( 7, java.lang.String(prov.os));
+      stmt.setObject( 8, java.lang.String(tdate));
+      stmt.setObject( 9, java.lang.String(author));
+      stmt.setObject(10, objid);
+      stmt.executeUpdate();
+      stmt.close();
+    else
+      
+      % reference IDs are stored in a CSV string
+      if ischar(sinfo.reference_ids)
+        refids = sinfo.reference_ids;
+      else
+        refids = utils.prog.csv(sinfo.reference_ids);
+      end
+      
+      stmt = c.prepareStatement(...
+        [ 'UPDATE objmeta SET obj_type=?, name=?, created=?, version=?, ' ...
+        'ip=?, hostname=?, os=?, submitted=?, experiment_title=?, experiment_desc=?, ' ...
+        'reference_ids=?, additional_comments=?, additional_authors=?, keywords=?, ' ...
+        'quantity=?, analysis_desc=?, author=? WHERE obj_id=?' ]);
+      stmt.setObject( 1, java.lang.String(class(obj)));
+      stmt.setObject( 2, java.lang.String(obj.name));
+      stmt.setObject( 3, java.lang.String(created));
+      stmt.setObject( 4, java.lang.String(getappdata(0, 'ltpda_version')));
+      stmt.setObject( 5, java.lang.String(prov.ip));
+      stmt.setObject( 6, java.lang.String(prov.hostname));
+      stmt.setObject( 7, java.lang.String(prov.os));
+      stmt.setObject( 8, java.lang.String(tdate));
+      stmt.setObject( 9, java.lang.String(sinfo.experiment_title));
+      stmt.setObject(10, java.lang.String(sinfo.experiment_description));
+      stmt.setObject(11, java.lang.String(refids));
+      stmt.setObject(12, java.lang.String(sinfo.additional_comments));
+      stmt.setObject(13, java.lang.String(sinfo.additional_authors));
+      stmt.setObject(14, java.lang.String(sinfo.keywords));
+      stmt.setObject(15, java.lang.String(sinfo.quantity));
+      stmt.setObject(16, java.lang.String(sinfo.analysis_description));
+      stmt.setObject(17, java.lang.String(author));
+      stmt.setObject(18, objid);
+      stmt.executeUpdate();
+      stmt.close();
+    end
+    
+    % update other meta-data tables
+    cols = utils.jmysql.execute(c, 'SHOW COLUMNS FROM tsdata');
+    if utils.helper.ismember('obj_id',  cols(:,1))
+      % the tsdata table contains an obj id column. use the new database schema
+      utils.jmysql.updateObjMetadata(c, obj, objid);
+    else
+      % otherwise use the old one
+      utils.helper.msg(msg.PROC2, 'using back-compatibility code');
+      utils.jmysql.updateObjMetadataV1(c, obj, objid);
+    end
+    
+  catch ex
+    utils.helper.msg(msg.IMPORTANT, 'update error. no object updated')
+    c.close()
+    conn.setLocked(false);
+    rethrow(ex)
+  end
+  
+  % commit the transaction
+  c.commit();
+  
+  conn.setLocked(false);
+  
+  % reset timer
+  rm = LTPDARepositoryManager();
+  LTPDARepositoryManager.resetTimer(rm.timerClearPass, conn);
+  LTPDARepositoryManager.resetTimer(rm.timerDisconnect, conn);
+  
+end
+
+
+function result = changeSinfo(pl)
+  % checks if a user wants to update the sinfo of an object
+  result = ...
+    ~isempty(pl.find('experiment_title'))       || ...
+    ~isempty(pl.find('experiment title'))       || ...
+    ~isempty(pl.find('experiment_description')) || ...
+    ~isempty(pl.find('experiment description')) || ...
+    ~isempty(pl.find('analysis_description'))   || ...
+    ~isempty(pl.find('analysis description'))   || ...
+    ~isempty(pl.find('quantity'))               || ...
+    ~isempty(pl.find('keywords'))               || ...
+    ~isempty(pl.find('reference_ids'))          || ...
+    ~isempty(pl.find('reference ids'))          || ...
+    ~isempty(pl.find('additional_comments'))    || ...
+    ~isempty(pl.find('additional comments'))    || ...
+    ~isempty(pl.find('additional_authors'))     || ...
+    ~isempty(pl.find('additional authors'));
+end
+
+
+function ii = getInfo(varargin)
+  if nargin == 1 && strcmpi(varargin{1}, 'None')
+    sets = {};
+    pl   = [];
+  else
+    sets = {'Default'};
+    pl   = getDefaultPlist();
+  end
+  % Build info object
+  ii = minfo(mfilename, 'ltpda_uo', 'ltpda', utils.const.categories.internal, '$Id: update.m,v 1.45 2011/11/18 08:09:45 mauro Exp $', sets, pl);
+  ii.setModifier(false);
+end
+
+
+function plout = getDefaultPlist()
+  persistent pl;
+  if ~exist('pl', 'var') || isempty(pl)
+    pl = buildplist();
+  end
+  plout = pl;
+end
+
+function plo = buildplist()
+  
+  plo = plist.TO_REPOSITORY_PLIST;
+  
+  p = param({'binary', 'Update only binary version of the objects'}, paramValue.FALSE_TRUE);
+  plo.append(p);
+end
+