MatrixBerryCore
ConfRepoManagerAnyStorage.m
Go to the documentation of this file.
1 classdef ConfRepoManagerAnyStorage<mxberry.core.obj.HandleObjectCloner
2  properties (Access=private)
3  storage
4  cache
5  curConfName='';
6  getStorageHook
7  putStorageHook
8  end
9  properties (SetAccess=private,GetAccess=protected)
10  confPatchRepo
11  end
12  methods
13  function storageDir=getStorageBranchKey(self)
14  storageDir=self.storage.getStorageBranchKey();
15  end
16  %
17  function storageDir=getStorageLocation(self)
18  storageDir=self.storage.getStorageLocation();
19  end
20  %
21  function storageRootDir=getStorageLocationRoot(self)
22  storageRootDir=self.storage.getStorageLocationRoot();
23  end
24  end
25  %
26  methods (Access=private)
27  function [SConfData,metaData]=getConfFromStorage(self,confName)
28  [SConfData,metaData]=self.storage.get(confName);
29  SConfData=...
30  mxberry.core.struct.updateleaves(SConfData,self.getStorageHook);
31  end
32  %
33  end
34  methods
35  function isPositive=isCachedConf(self,confName)
36  isPositive=self.cache.isKey(confName);
37  end
38  function putConfToCache(self,varargin)
39  self.cacheConf(varargin{:});
40  end
41  function putConfToCacheAndSelect(self,varargin)
42  self.cacheAndSelectConf(varargin{:});
43  end
44  function putConfToStorage(self,confName,SConfData,metaData)
45  SConfData=...
46  mxberry.core.struct.updateleaves(SConfData,...
47  self.putStorageHook);
48  self.storage.put(confName,SConfData,metaData);
49  end
50  end
51  %
52  methods (Access=protected,Static)
53  function confVersion=getConfVersionFromMetaData(metaData)
54  if ~isfield(metaData,'version')
55  confVersion=-Inf;
56  else
57  confVersion=str2double(metaData.version);
58  end
59  end
60  function metaData=putConfVersionToMetaData(metaData,confVersion)
61  confVersion=num2str(confVersion);
62  metaData.version=confVersion;
63  end
64  end
65  methods
66  function otherObj=getCopy(self)
67  otherObj=getArrayFromByteStream(getByteStreamFromArray(self));
68  end
69  function isPos=isConfSelected(self,confName)
70  isPos=strcmp(self.curConfName,confName);
71  end
72  function storeCachedConf(self,confName)
73  [SConfData,metaData]=getCachedConf(self,confName);
74  self.putConfToStorage(confName,SConfData,metaData)
75  end
76  function flushCache(self)
77  self.initCache();
78  end
79  function lastRevision=getLastConfVersion(self)
80  lastRevision=self.confPatchRepo.getLastRevision();
81  end
82  function self=ConfRepoManagerAnyStorage(storage,varargin)
83  import mxberry.core.parseparext;
84  import mxberry.core.struct.*;
85  mxberry.core.checkvar(storage,...
86  @(x)isa(x,...
87  'mxberry.core.cont.ondisk.IOnDiskBranchedStorage'));
88 
89  self.initCache();
90  %
91  [reg,isRegSpec,self.putStorageHook,...
92  self.getStorageHook]=parseparext(...
93  varargin,{...
94  'putStorageHook','getStorageHook';...
95  @(x,y)x,@(x,y)x;...
96  @(x)isa(x,'function_handle'),...
97  @(x)isa(x,'function_handle')},...
98  'regCheckList',...
99  {@(x)isa(x,...
100  'mxberry.core.struct.AStructChangeTracker')});
101 
102  if isRegSpec
103  self.confPatchRepo=reg{1};
104  else
105  self.confPatchRepo=...
106  StructChangeTrackerEmptyPlug();
107  end
108  %
109  self.storage=storage;
110  %
111  end
112  %
113  function editConf(self,confName)
114  fileName=self.storage.getFileNameByKey(confName);
115  edit(fileName);
116  end
117  %
118  function selectConf(self,confName,varargin)
119  import mxberry.core.throwerror;
120  [~,prop]=mxberry.core.parseparams(varargin,{'reloadIfSelected'},0);
121  if ~isempty(prop)
122  isReloadedIfSelected=prop{2};
123  if ~(islogical(isReloadedIfSelected)&&numel(isReloadedIfSelected)==1)
124  throwerror('wrongInput',...
125  'reloadedIfSelected is expected to be a logical scalar');
126  end
127  else
128  isReloadedIfSelected=true;
129  end
130  %
131  if isReloadedIfSelected||~(isReloadedIfSelected||self.isCachedConf(confName))
132  if ~self.storage.isKey(confName)
133  throwerror('unknownConfig',...
134  'configuration %s does not exist in the repository',...
135  confName);
136  end
137  %
138  [SConf,metaData]=self.getConfFromStorage(confName);
139  self.cacheAndSelectConf(confName,SConf,metaData);
140  else
141  self.curConfName=confName;
142  end
143  end
144  %
145  function isPositive=isParam(self,paramName)
146  if paramName(1)~='.'
147  paramName=['.',paramName];
148  end
149  isPositive=mxberry.core.struct.structcheckpath(...
150  self.getCurConf(),paramName);
151  end
152  %
153  function resVal=getParam(self,paramName,varargin)
154  import mxberry.core.throwerror;
155  import mxberry.core.parseparext;
156  %
157  [~,~,isCacheSkipped]=parseparext(varargin,...
158  {'skipCache';false;@(x)islogical(x)&&isscalar(x)},0);
159  %
160  if isCacheSkipped
161  self.reCacheCurConf();
162  end
163  try
164  resVal=mxberry.core.struct.structgetpath(self.getCurConf(),...
165  paramName);
166  %
167  catch meObj
168  newMeObj=throwerror('invalidParam',...
169  'the requested parameter does not exist');
170  newMeObj=newMeObj.addCause(meObj);
171  throw(newMeObj);
172  end
173  end
174  %
175  function setParam(self,paramName,paramValue,varargin)
176  [~,prop]=mxberry.core.parseparams(varargin,{'writedepth'},0);
177  isWriteToDisk=true;
178  if ~isempty(prop)
179  isWriteToDisk=strcmpi(prop{2},'disk');
180  end
181  %
182  if paramName(1)~='.'
183  paramName=['.',paramName];
184  end
185  %
186  curConfName=self.getCurConfName(); %#ok<*PROPLC,*PROP>
187  [curConf,metaData]=self.getCurConf();
188  SConf=mxberry.core.struct.structapplypath(curConf,paramName,...
189  paramValue);
190  %
191  self.cacheAndSelectConf(curConfName,SConf,metaData);
192  if isWriteToDisk
193  self.putConfToStorage(curConfName,SConf,metaData);
194  end
195  end
196  %
197  function putConf(self,confName,SConf,varargin)
198  [restArgList,~,isSelected]=mxberry.core.parseparext(varargin,...
199  {'selectConf';true;'islogical(x)&&isscalar(x)'});
200  %
201  self.putConfInternal(confName,SConf,restArgList{:});
202  %
203  if isSelected
204  self.curConfName=confName;
205  end
206  %
207  end
208  %
209  function [SConf,confVersion,metaData]=getConf(self,confName)
210  [SConf,confVersion,metaData]=self.getConfInternal(confName);
211  end
212  %
213  function copyConf(self,fromConfName,toConfName)
214  [SConf,metaData]=self.getConfInternal(fromConfName);
215  self.putConf(toConfName,SConf,metaData);
216  end
217  %
218  function destFileName=copyConfFile(self,destFolderName,varargin)
219  [reg,~,isDestFile]=mxberry.core.parseparext(varargin,...
220  {'destIsFile';false;'isscalar(x)&&islogical(x)'},...
221  'regCheckList',{'isstring(x)'},...
222  'regDefList',{self.getCurConfName()});
223  confName=reg{1};
224 
225  fullFileName=self.storage.getFileNameByKey(confName);
226  %make sure that "/" at the end of folder path doesn't matter
227  if isDestFile
228  destFileName=destFolderName;
229  else
230  [~,fileName,ext]=fileparts(fullFileName);
231  if strcmp(destFolderName(end),filesep)
232  destFolderName=destFolderName(1:end-1);
233  end
234  if ~mxberry.io.isdir(destFolderName)
235  mxberry.io.mkdir(destFolderName);
236  end
237  destFileName=[destFolderName,filesep,fileName,ext];
238  end
239  copyfile(fullFileName,destFileName);
240  end
241  %
242  function removeAll(self)
243  self.initCache();
244  self.storage.removeAll();
245  end
246  function confNameList=getConfNameList(self)
247  confNameList=self.getConfNameListInternal();
248  end
249  function confName=getCurConfName(self)
250  import mxberry.core.throwerror;
251  if isempty(self.curConfName)
252  throwerror('wrongActionSequence',...
253  'Current configuration is not selected');
254  end
255  %
256  confName=self.curConfName;
257  end
258  %
259  function [SConf,metaData]=getCurConf(self)
260  curConfName=self.getCurConfName();
261  [SConf,metaData]=self.getCachedConf(curConfName);
262  end
263  %
264  function isPositive=isConf(self,confName)
265  isPositive=self.storage.isKey(confName);
266  end
267  function removeConf(self,confName)
268  if self.cache.isKey(confName)
269  self.cache.remove(confName);
270  end
271  %
272  self.storage.remove(confName);
273  end
274  function setConfPatchRepo(self,confPatchRepo)
275  self.confPatchRepo=confPatchRepo;
276  end
277  function updateConf(self,confName)
278  self.updateConfInternal(confName);
279  end
280  function updateAll(self)
281  self.updateAllInternal();
282  end
283  end
284  methods (Access=protected)
285  function confNameList=getCachedConfNames(self)
286  confNameList=self.cache.keys();
287  end
288  %
289  function updateAllInternal(self)
290  confNameList=self.getConfNameListInternal();
291  nConfs=length(confNameList);
292  for iConf=1:nConfs
293  confName=confNameList{iConf};
294  self.updateConfInternal(confName);
295  end
296  end
297  %
298  function confNameList=getConfNameListInternal(self)
299  import mxberry.core.throwerror;
300  try
301  confNameList=self.storage.getKeyList();
302  catch meObj
303  if ~isempty(strfind(meObj.identifier,':badKeyValuePair'))
304  newMeObj=throwerror('badConfRepo',...
305  ['configuration repository contains the ',...
306  'inconsistent configurations']);
307  newMeObj=addCause(newMeObj,meObj);
308  throw(newMeObj);
309  else
310  rethrow(meObj);
311  end
312  end
313  end
314  function updateConfInternal(self,confName)
315  [SConf,oldConfVersion,metaData]=self.getConfInternal(confName);
316  [SConf,confVersion,metaData]=self.updateConfStructInternal(...
317  SConf,oldConfVersion,metaData);
318  if (confVersion>oldConfVersion)||isnan(oldConfVersion)
319  self.putConfInternal(confName,SConf,confVersion,metaData);
320  end
321  end
322  function [SConf,confVersion,metaData]=updateConfStructInternal(self,SConf,confVersion,metaData)
323  [SConf,confVersion]=self.confPatchRepo.applyAllLaterPatches(SConf,confVersion);
324  metaData=self.putConfVersionToMetaData(metaData,confVersion);
325 
326  end
327 
328  function [SConf,confVersion,metaData]=getConfInternal(self,confName)
329  import mxberry.core.throwerror;
330  %
331  if self.isCachedConf(confName)
332  [SConf,metaData]=self.getCachedConf(confName);
333  else
334  try
335  [SConf,metaData]=self.getConfFromStorage(confName);
336  catch meObj
337  if ~isempty(strfind(meObj.identifier,':noRecord'))
338  newMeObj=throwerror('noConfiguration',...
339  'configuration %s does not exist',confName);
340  %
341  newMeObj=addCause(newMeObj,meObj);
342  throw(newMeObj);
343  else
344  rethrow(meObj);
345  end
346  end
347  end
348  confVersion=self.getConfVersionFromMetaData(metaData);
349  end
350  %
351  function putConfInternal(self,confName,SConf,confVersion,metaData)
352  if nargin<5
353  metaData=struct();
354  end
355  %
356  if nargin<4
357  confVersion=self.confPatchRepo.getLastRevision();
358  end
359  %
360  metaData=self.putConfVersionToMetaData(metaData,confVersion);
361  %
362  self.cacheConf(confName,SConf,metaData);
363  self.putConfToStorage(confName,SConf,metaData);
364  end
365  %
366  end
367  methods (Access=protected)
368  function cacheAndSelectConf(self,confName,SConf,metaData)
369  self.cacheConf(confName,SConf,metaData);
370  self.curConfName=confName;
371  end
372  function cacheConf(self,confName,SConf,metaData)
373  self.cache(confName)={SConf,metaData};
374  end
375  function [SConf,metaData]=getCachedConf(self,confName)
376  import mxberry.core.throwerror;
377  isCached=self.isCachedConf(confName);
378  if isCached
379  res=self.cache(confName);
380  SConf=res{1};
381  metaData=res{2};
382  else
383  throwerror('noKey',...
384  'configuration %s is not cached',confName);
385  end
386  end
387  function reCacheCurConf(self)
388  curConfName=self.getCurConfName();
389  [conf,metaData]=self.getConfFromStorage(curConfName);
390  self.cacheAndSelectConf(curConfName,conf,metaData);
391  end
392  function initCache(self)
393  self.cache=containers.Map;
394  end
395  end
396 end
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function parseparext(in args, in propNameValMat, in varargin)
PARSEPAREXT behaves in the same way as mxberry.core.parseparams but returns property values in a more...
function checkvar(in x, in typeSpec, in varargin)
CHECKVAR checks a generic condition provided by typeSpec string in the following format: &#39;isnumeric(x...
HANDLEOBJECTCLONER provides some simple functionality for clonable objects.
function updateleaves(in SData, in fUpdateFunc)
UPDATELEAVES applies the specified function to each structure leave value and returns the updated str...