2010-10-20 22:45:52 +02:00
/ *
Copyright 2010 , Google Inc .
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are
met :
* Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the following disclaimer
in the documentation and / or other materials provided with the
distribution .
* Neither the name of Google Inc . nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
2010-09-22 19:04:10 +02:00
package com.google.refine ;
2010-05-05 01:24:48 +02:00
2010-06-16 09:44:46 +02:00
import java.io.IOException ;
import java.io.InputStream ;
2010-06-20 18:32:49 +02:00
import java.util.ArrayList ;
import java.util.Collections ;
import java.util.Comparator ;
import java.util.Date ;
2010-06-21 21:57:31 +02:00
import java.util.HashMap ;
2010-05-05 01:24:48 +02:00
import java.util.List ;
import java.util.Map ;
import java.util.Map.Entry ;
2017-11-17 20:38:02 +01:00
import org.apache.commons.lang.exception.ExceptionUtils ;
2010-06-16 09:44:46 +02:00
import org.apache.tools.tar.TarOutputStream ;
2017-11-17 20:38:02 +01:00
import org.json.JSONArray ;
import org.json.JSONException ;
import org.json.JSONObject ;
2010-05-05 01:24:48 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2010-09-22 19:04:10 +02:00
import com.google.refine.history.HistoryEntryManager ;
import com.google.refine.model.Project ;
import com.google.refine.preference.PreferenceStore ;
import com.google.refine.preference.TopList ;
2010-05-05 01:24:48 +02:00
2010-06-21 21:57:31 +02:00
/ * *
* ProjectManager is responsible for loading and saving the workspace and projects .
*
*
* /
2010-06-15 21:34:40 +02:00
public abstract class ProjectManager {
2010-05-05 01:24:48 +02:00
// last n expressions used across all projects
static protected final int s_expressionHistoryMax = 100 ;
2010-06-15 21:34:40 +02:00
2013-08-10 01:53:53 +02:00
// If a project has been idle this long, flush it from memory
static protected final int PROJECT_FLUSH_DELAY = 1000 * 60 * 15 ; // 15 minutes
// Don't spend more than this much time saving projects if doing a quick save
static protected final int QUICK_SAVE_MAX_TIME = 1000 * 30 ; // 30 secs
2010-05-05 01:24:48 +02:00
protected Map < Long , ProjectMetadata > _projectsMetadata ;
2017-11-24 20:19:49 +01:00
protected Map < String , Integer > _projectsTags ; // TagName, number of projects having that tag
2010-06-17 04:15:26 +02:00
protected PreferenceStore _preferenceStore ;
2010-06-15 21:34:40 +02:00
2012-03-08 15:53:27 +01:00
final static Logger logger = LoggerFactory . getLogger ( " ProjectManager " ) ;
2010-06-15 21:34:40 +02:00
2010-05-05 01:24:48 +02:00
/ * *
* What caches the joins between projects .
* /
2010-05-09 06:34:36 +02:00
transient protected InterProjectModel _interProjectModel = new InterProjectModel ( ) ;
2010-06-15 21:34:40 +02:00
2010-05-09 06:34:36 +02:00
/ * *
2011-08-29 00:00:02 +02:00
* Flag for heavy operations like creating or importing projects . Workspace saves are skipped while it ' s set .
2010-05-09 06:34:36 +02:00
* /
2011-08-29 00:00:02 +02:00
transient protected int _busy = 0 ;
2010-06-15 21:34:40 +02:00
/ * *
* While each project ' s metadata is loaded completely at start - up , each project ' s raw data
* is loaded only when the project is accessed by the user . This is because project
* metadata is tiny compared to raw project data . This hash map from project ID to project
* is more like a last accessed - last out cache .
* /
transient protected Map < Long , Project > _projects ;
2010-05-05 01:24:48 +02:00
static public ProjectManager singleton ;
2010-06-15 21:34:40 +02:00
2010-06-21 21:57:31 +02:00
protected ProjectManager ( ) {
_projectsMetadata = new HashMap < Long , ProjectMetadata > ( ) ;
_preferenceStore = new PreferenceStore ( ) ;
_projects = new HashMap < Long , Project > ( ) ;
2017-11-24 20:19:49 +01:00
_projectsTags = new HashMap < String , Integer > ( ) ;
2010-06-21 21:57:31 +02:00
preparePreferenceStore ( _preferenceStore ) ;
}
2010-08-22 07:06:36 +02:00
public void dispose ( ) {
save ( true ) ; // complete save
for ( Project project : _projects . values ( ) ) {
2010-09-17 08:52:10 +02:00
if ( project ! = null ) {
project . dispose ( ) ;
}
2010-08-22 07:06:36 +02:00
}
_projects . clear ( ) ;
_projectsMetadata . clear ( ) ;
}
2010-06-21 21:57:31 +02:00
2010-06-18 21:16:30 +02:00
/ * *
* Registers the project in the memory of the current session
* @param project
* @param projectMetadata
* /
2010-05-05 01:24:48 +02:00
public void registerProject ( Project project , ProjectMetadata projectMetadata ) {
synchronized ( this ) {
_projects . put ( project . id , project ) ;
_projectsMetadata . put ( project . id , projectMetadata ) ;
2017-11-24 20:19:49 +01:00
if ( _projectsTags = = null )
_projectsTags = new HashMap < String , Integer > ( ) ;
for ( String tag : projectMetadata . getTags ( ) ) {
if ( _projectsTags . containsKey ( tag ) ) {
_projectsTags . put ( tag , _projectsTags . get ( tag ) + 1 ) ;
} else {
_projectsTags . put ( tag , 1 ) ;
}
}
2010-05-05 01:24:48 +02:00
}
}
2010-06-15 21:34:40 +02:00
2010-06-17 17:37:28 +02:00
/ * *
2010-06-20 18:32:49 +02:00
* Load project metadata from data storage
2010-06-17 17:37:28 +02:00
* @param projectID
* @return
* /
2010-06-20 18:32:49 +02:00
public abstract boolean loadProjectMetadata ( long projectID ) ;
2010-06-15 21:34:40 +02:00
2010-06-20 18:32:49 +02:00
/ * *
* Loads a project from the data store into memory
* @param id
* @return
* /
protected abstract Project loadProject ( long id ) ;
2010-06-17 17:37:28 +02:00
/ * *
2012-10-19 01:40:31 +02:00
* Import project from a Refine archive
2010-06-17 17:37:28 +02:00
* @param projectID
* @param inputStream
* @param gziped
* @throws IOException
* /
2010-06-16 09:44:46 +02:00
public abstract void importProject ( long projectID , InputStream inputStream , boolean gziped ) throws IOException ;
2010-06-17 17:37:28 +02:00
/ * *
2012-10-19 01:40:31 +02:00
* Export project to a Refine archive
2010-06-17 17:37:28 +02:00
* @param projectId
* @param tos
* @throws IOException
* /
2010-06-16 09:44:46 +02:00
public abstract void exportProject ( long projectId , TarOutputStream tos ) throws IOException ;
2010-06-20 18:32:49 +02:00
2010-06-18 21:16:30 +02:00
/ * *
2010-06-18 22:47:15 +02:00
* Saves a project and its metadata to the data store
2010-06-18 21:16:30 +02:00
* @param id
* /
2010-06-18 22:47:15 +02:00
public void ensureProjectSaved ( long id ) {
synchronized ( this ) {
2010-06-21 21:57:31 +02:00
ProjectMetadata metadata = this . getProjectMetadata ( id ) ;
2010-06-18 22:47:15 +02:00
if ( metadata ! = null ) {
try {
saveMetadata ( metadata , id ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
2010-06-21 21:57:31 +02:00
} //FIXME what should be the behaviour if metadata is null? i.e. not found
2010-06-18 22:47:15 +02:00
2010-06-21 21:57:31 +02:00
Project project = getProject ( id ) ;
if ( project ! = null & & metadata ! = null & & metadata . getModified ( ) . after ( project . getLastSave ( ) ) ) {
2010-06-18 22:47:15 +02:00
try {
saveProject ( project ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
}
2010-06-21 21:57:31 +02:00
} //FIXME what should be the behaviour if project is null? i.e. not found or loaded.
//FIXME what should happen if the metadata is found, but not the project? or vice versa?
2010-06-18 22:47:15 +02:00
}
}
2010-06-21 21:57:31 +02:00
2010-06-20 18:32:49 +02:00
/ * *
* Save project metadata to the data store
* @param metadata
* @param projectId
* @throws Exception
* /
2017-10-26 21:45:58 +02:00
public abstract void saveMetadata ( ProjectMetadata metadata , long projectId ) throws Exception ;
2010-06-20 18:32:49 +02:00
/ * *
* Save project to the data store
* @param project
2013-08-05 20:13:56 +02:00
* @throws IOException
2010-06-20 18:32:49 +02:00
* /
2013-08-05 20:13:56 +02:00
protected abstract void saveProject ( Project project ) throws IOException ;
2010-06-15 21:34:40 +02:00
2010-06-20 18:32:49 +02:00
/ * *
* Save workspace and all projects to data store
2010-06-21 21:57:31 +02:00
* @param allModified
2010-06-20 18:32:49 +02:00
* /
public void save ( boolean allModified ) {
if ( allModified | | _busy = = 0 ) {
saveProjects ( allModified ) ;
saveWorkspace ( ) ;
}
}
/ * *
* Saves the workspace to the data store
* /
protected abstract void saveWorkspace ( ) ;
/ * *
* A utility class to prioritize projects for saving , depending on how long ago
* they have been changed but have not been saved .
* /
static protected class SaveRecord {
final Project project ;
final long overdue ;
SaveRecord ( Project project , long overdue ) {
this . project = project ;
this . overdue = overdue ;
}
}
/ * *
* Saves all projects to the data store
* @param allModified
* /
protected void saveProjects ( boolean allModified ) {
List < SaveRecord > records = new ArrayList < SaveRecord > ( ) ;
2010-06-21 21:57:31 +02:00
Date startTimeOfSave = new Date ( ) ;
2010-10-14 03:43:26 +02:00
2010-06-20 18:32:49 +02:00
synchronized ( this ) {
for ( long id : _projectsMetadata . keySet ( ) ) {
2010-06-21 21:57:31 +02:00
ProjectMetadata metadata = getProjectMetadata ( id ) ;
2010-06-26 00:43:30 +02:00
Project project = _projects . get ( id ) ; // don't call getProject() as that will load the project.
2010-06-20 18:32:49 +02:00
if ( project ! = null ) {
boolean hasUnsavedChanges =
2010-10-14 03:43:26 +02:00
metadata . getModified ( ) . getTime ( ) > = project . getLastSave ( ) . getTime ( ) ;
// We use >= instead of just > to avoid the case where a newly created project
// has the same modified and last save times, resulting in the project not getting
// saved at all.
2010-06-20 18:32:49 +02:00
if ( hasUnsavedChanges ) {
2010-06-21 21:57:31 +02:00
long msecsOverdue = startTimeOfSave . getTime ( ) - project . getLastSave ( ) . getTime ( ) ;
2010-06-20 18:32:49 +02:00
records . add ( new SaveRecord ( project , msecsOverdue ) ) ;
2011-08-29 00:00:02 +02:00
} else if ( ! project . getProcessManager ( ) . hasPending ( )
2013-08-10 01:53:53 +02:00
& & startTimeOfSave . getTime ( ) - project . getLastSave ( ) . getTime ( ) > PROJECT_FLUSH_DELAY ) {
2011-08-29 00:00:02 +02:00
2010-06-20 18:32:49 +02:00
/ *
* It ' s been a while since the project was last saved and it hasn ' t been
* modified . We can safely remove it from the cache to save some memory .
* /
2010-08-22 07:06:36 +02:00
_projects . remove ( id ) . dispose ( ) ;
2010-06-20 18:32:49 +02:00
}
}
}
}
2010-10-14 03:43:26 +02:00
2010-06-20 18:32:49 +02:00
if ( records . size ( ) > 0 ) {
Collections . sort ( records , new Comparator < SaveRecord > ( ) {
2011-08-02 21:30:23 +02:00
@Override
2010-06-20 18:32:49 +02:00
public int compare ( SaveRecord o1 , SaveRecord o2 ) {
if ( o1 . overdue < o2 . overdue ) {
return 1 ;
} else if ( o1 . overdue > o2 . overdue ) {
return - 1 ;
} else {
return 0 ;
}
}
} ) ;
logger . info ( allModified ?
" Saving all modified projects ... " :
" Saving some modified projects ... "
) ;
for ( int i = 0 ;
i < records . size ( ) & &
2013-08-10 01:53:53 +02:00
( allModified | | ( new Date ( ) . getTime ( ) - startTimeOfSave . getTime ( ) < QUICK_SAVE_MAX_TIME ) ) ;
2010-06-20 18:32:49 +02:00
i + + ) {
try {
saveProject ( records . get ( i ) . project ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
2013-08-05 20:13:56 +02:00
// In case we're running low on memory, free as much as we can
disposeUnmodifiedProjects ( ) ;
}
}
}
}
/ * *
* Flush all unmodified projects from memory .
* /
protected void disposeUnmodifiedProjects ( ) {
synchronized ( this ) {
for ( long id : _projectsMetadata . keySet ( ) ) {
ProjectMetadata metadata = getProjectMetadata ( id ) ;
Project project = _projects . get ( id ) ;
if ( project ! = null & & ! project . getProcessManager ( ) . hasPending ( )
& & metadata . getModified ( ) . getTime ( ) < project . getLastSave ( ) . getTime ( ) ) {
_projects . remove ( id ) . dispose ( ) ;
2010-06-20 18:32:49 +02:00
}
}
}
}
/ * *
* Gets the InterProjectModel from memory
* /
public InterProjectModel getInterProjectModel ( ) {
return _interProjectModel ;
}
/ * *
* Gets the project metadata from memory
* Requires that the metadata has already been loaded from the data store
* @param id
* @return
* /
2010-05-05 01:24:48 +02:00
public ProjectMetadata getProjectMetadata ( long id ) {
return _projectsMetadata . get ( id ) ;
}
2010-06-15 21:34:40 +02:00
2010-06-18 21:16:30 +02:00
/ * *
2010-06-20 18:32:49 +02:00
* Gets the project metadata from memory
* Requires that the metadata has already been loaded from the data store
2010-06-18 21:16:30 +02:00
* @param name
* @return
* /
2010-05-05 01:24:48 +02:00
public ProjectMetadata getProjectMetadata ( String name ) {
for ( ProjectMetadata pm : _projectsMetadata . values ( ) ) {
if ( pm . getName ( ) . equals ( name ) ) {
return pm ;
}
}
return null ;
}
2010-06-15 21:34:40 +02:00
2010-06-18 21:16:30 +02:00
/ * *
* Tries to find the project id when given a project name
2010-06-20 18:32:49 +02:00
* Requires that all project metadata exists has been loaded to memory from the data store
2010-06-18 21:16:30 +02:00
* @param name
* The name of the project
* @return
* The id of the project , or - 1 if it cannot be found
* /
2010-05-05 01:24:48 +02:00
public long getProjectID ( String name ) {
for ( Entry < Long , ProjectMetadata > entry : _projectsMetadata . entrySet ( ) ) {
if ( entry . getValue ( ) . getName ( ) . equals ( name ) ) {
return entry . getKey ( ) ;
}
}
return - 1 ;
}
2017-11-17 20:38:02 +01:00
/ * *
* A valid user meta data definition should have name and display property
* @param placeHolderJsonObj
* @return
* /
private boolean isValidUserMetadataDefinition ( JSONObject placeHolderJsonObj ) {
return ( placeHolderJsonObj ! = null & &
placeHolderJsonObj . has ( " name " ) & &
placeHolderJsonObj . has ( " display " ) ) ;
}
public void mergeEmptyUserMetadata ( ProjectMetadata metadata ) {
if ( metadata = = null )
return ;
// place holder
JSONArray userMetadataPreference = null ;
// actual metadata for project
JSONArray jsonObjArray = metadata . getUserMetadata ( ) ;
2017-11-18 04:55:16 +01:00
initDisplay ( jsonObjArray ) ;
2017-11-17 20:38:02 +01:00
try {
String userMeta = ( String ) _preferenceStore . get ( PreferenceStore . USER_METADATA_KEY ) ;
if ( userMeta = = null )
return ;
userMetadataPreference = new JSONArray ( userMeta ) ;
} catch ( JSONException e1 ) {
logger . warn ( " wrong definition of userMetadata format. Please use form [{ \" name \" : \" client name \" , \" display \" :true}, { \" name \" : \" progress \" , \" display \" :false}] " ) ;
2017-11-17 22:58:30 +01:00
logger . error ( ExceptionUtils . getFullStackTrace ( e1 ) ) ;
2017-11-17 20:38:02 +01:00
}
for ( int index = 0 ; index < userMetadataPreference . length ( ) ; index + + ) {
try {
boolean found = false ;
JSONObject placeHolderJsonObj = userMetadataPreference . getJSONObject ( index ) ;
if ( ! isValidUserMetadataDefinition ( placeHolderJsonObj ) ) {
logger . warn ( " Skipped invalid user metadata definition " + placeHolderJsonObj . toString ( ) ) ;
continue ;
}
2010-06-15 21:34:40 +02:00
2017-11-17 20:38:02 +01:00
for ( int i = 0 ; i < jsonObjArray . length ( ) ; i + + ) {
JSONObject jsonObj = jsonObjArray . getJSONObject ( i ) ;
if ( jsonObj . getString ( " name " ) . equals ( placeHolderJsonObj . getString ( " name " ) ) ) {
found = true ;
jsonObj . put ( " display " , placeHolderJsonObj . get ( " display " ) ) ;
break ;
}
}
if ( ! found ) {
placeHolderJsonObj . put ( " value " , " " ) ;
metadata . getUserMetadata ( ) . put ( placeHolderJsonObj ) ;
logger . info ( " Put the placeholder {} for project {} " ,
placeHolderJsonObj . getString ( " name " ) ,
metadata . getName ( ) ) ;
}
} catch ( JSONException e ) {
logger . warn ( " Exception when mergeEmptyUserMetadata " , e ) ;
}
}
}
2017-11-17 22:52:26 +01:00
/ * *
* honor the meta data preference
* @param jsonObjArray
* /
2017-11-18 04:55:16 +01:00
private void initDisplay ( JSONArray jsonObjArray ) {
2017-11-17 22:52:26 +01:00
for ( int index = 0 ; index < jsonObjArray . length ( ) ; index + + ) {
try {
JSONObject projectMetaJsonObj = jsonObjArray . getJSONObject ( index ) ;
projectMetaJsonObj . put ( " display " , false ) ;
} catch ( JSONException e ) {
logger . error ( ExceptionUtils . getFullStackTrace ( e ) ) ;
}
}
}
2010-06-15 21:34:40 +02:00
2010-06-20 18:32:49 +02:00
/ * *
2017-11-17 20:38:02 +01:00
* Gets all the project Metadata currently held in memory .
2010-06-20 18:32:49 +02:00
* @return
* /
2010-05-05 01:24:48 +02:00
public Map < Long , ProjectMetadata > getAllProjectMetadata ( ) {
2017-11-17 20:38:02 +01:00
for ( Project project : _projects . values ( ) ) {
mergeEmptyUserMetadata ( project . getMetadata ( ) ) ;
}
2010-05-05 01:24:48 +02:00
return _projectsMetadata ;
}
2017-11-24 20:19:49 +01:00
/ * *
* Gets all the project tags currently held in memory
*
* @return
* /
public Map < String , Integer > getAllProjectTags ( ) {
return _projectsTags ;
}
2010-06-15 21:34:40 +02:00
2010-06-18 21:16:30 +02:00
/ * *
* Gets the required project from the data store
2010-06-20 18:32:49 +02:00
* If project does not already exist in memory , it is loaded from the data store
2010-06-18 21:16:30 +02:00
* @param id
* the id of the project
* @return
* the project with the matching id , or null if it can ' t be found
* /
public Project getProject ( long id ) {
synchronized ( this ) {
if ( _projects . containsKey ( id ) ) {
return _projects . get ( id ) ;
} else {
Project project = loadProject ( id ) ;
2010-10-07 16:19:42 +02:00
if ( project ! = null ) {
_projects . put ( id , project ) ;
}
2010-06-18 21:16:30 +02:00
return project ;
}
}
}
/ * *
2010-06-20 18:32:49 +02:00
* Gets the preference store
* @return
2010-06-18 21:16:30 +02:00
* /
2010-06-17 04:15:26 +02:00
public PreferenceStore getPreferenceStore ( ) {
return _preferenceStore ;
}
2010-06-15 21:34:40 +02:00
2010-06-20 18:32:49 +02:00
/ * *
* Gets all expressions from the preference store
* @return
* /
2010-05-05 01:24:48 +02:00
public List < String > getExpressions ( ) {
2010-08-07 22:25:31 +02:00
return ( ( TopList ) _preferenceStore . get ( " scripting.expressions " ) ) . getList ( ) ;
2010-05-05 01:24:48 +02:00
}
2010-06-15 21:34:40 +02:00
2010-06-17 17:37:28 +02:00
/ * *
2010-06-20 18:32:49 +02:00
* The history entry manager deals with changes
* @return manager for handling history
2010-06-17 17:37:28 +02:00
* /
2010-06-20 18:32:49 +02:00
public abstract HistoryEntryManager getHistoryEntryManager ( ) ;
2010-06-15 21:34:40 +02:00
2010-06-18 21:16:30 +02:00
/ * *
* Remove the project from the data store
* @param project
* /
2010-05-05 01:24:48 +02:00
public void deleteProject ( Project project ) {
deleteProject ( project . id ) ;
}
2010-06-15 21:34:40 +02:00
2010-06-17 17:37:28 +02:00
/ * *
* Remove project from data store
* @param projectID
* /
2010-06-18 21:16:30 +02:00
public abstract void deleteProject ( long projectID ) ;
2010-06-20 18:32:49 +02:00
/ * *
* Removes project from memory
* @param projectID
* /
2010-06-18 21:16:30 +02:00
protected void removeProject ( long projectID ) {
2010-08-22 07:06:36 +02:00
if ( _projects . containsKey ( projectID ) ) {
_projects . remove ( projectID ) . dispose ( ) ;
}
2010-06-18 21:16:30 +02:00
if ( _projectsMetadata . containsKey ( projectID ) ) {
_projectsMetadata . remove ( projectID ) ;
}
}
2010-06-15 21:34:40 +02:00
2010-06-20 18:32:49 +02:00
2010-06-17 17:37:28 +02:00
/ * *
2011-08-29 00:00:02 +02:00
* Sets the flag for long running operations . This will prevent
* workspace saves from happening while it ' s set .
2010-06-20 18:32:49 +02:00
* @param busy
2010-06-17 17:37:28 +02:00
* /
2010-06-20 18:32:49 +02:00
public void setBusy ( boolean busy ) {
synchronized ( this ) {
if ( busy ) {
_busy + + ;
} else {
_busy - - ;
}
}
}
2010-06-18 21:16:30 +02:00
2010-06-20 18:32:49 +02:00
/ * *
* Add the latest expression to the preference store
* @param s
* /
public void addLatestExpression ( String s ) {
synchronized ( this ) {
2010-08-07 22:25:31 +02:00
( ( TopList ) _preferenceStore . get ( " scripting.expressions " ) ) . add ( s ) ;
2010-06-20 18:32:49 +02:00
}
2010-06-17 04:15:26 +02:00
}
2010-06-20 18:32:49 +02:00
/ * *
*
* @param ps
* /
static protected void preparePreferenceStore ( PreferenceStore ps ) {
2010-07-31 09:01:44 +02:00
ps . put ( " scripting.expressions " , new TopList ( s_expressionHistoryMax ) ) ;
2011-06-06 20:49:36 +02:00
ps . put ( " scripting.starred-expressions " , new TopList ( Integer . MAX_VALUE ) ) ;
2010-06-20 18:32:49 +02:00
}
2010-05-05 01:24:48 +02:00
}