/* * Created on May 6, 2008 * Created by Paul Gardner * * Copyright 2008 Vuze, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ package com.aelitis.azureus.core.metasearch.impl; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.URLDecoder; import java.util.*; import org.gudy.azureus2.core3.config.COConfigurationManager; import org.gudy.azureus2.core3.config.ParameterListener; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.util.AEDiagnostics; import org.gudy.azureus2.core3.util.BEncoder; import org.gudy.azureus2.core3.util.Base32; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.core3.util.RandomUtils; import org.gudy.azureus2.core3.util.UrlUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import com.aelitis.azureus.core.messenger.config.PlatformMetaSearchMessenger; import com.aelitis.azureus.core.metasearch.Engine; import com.aelitis.azureus.core.metasearch.Result; import com.aelitis.azureus.core.metasearch.ResultListener; import com.aelitis.azureus.core.metasearch.SearchException; import com.aelitis.azureus.core.metasearch.SearchLoginException; import com.aelitis.azureus.core.metasearch.SearchParameter; import com.aelitis.azureus.core.metasearch.impl.plugin.PluginEngine; import com.aelitis.azureus.core.metasearch.impl.web.json.JSONEngine; import com.aelitis.azureus.core.metasearch.impl.web.regex.RegexEngine; import com.aelitis.azureus.core.metasearch.impl.web.rss.RSSEngine; import com.aelitis.azureus.core.vuzefile.VuzeFile; import com.aelitis.azureus.core.vuzefile.VuzeFileComponent; import com.aelitis.azureus.core.vuzefile.VuzeFileHandler; import com.aelitis.azureus.util.ConstantsVuze; import com.aelitis.azureus.util.ImportExportUtils; import com.aelitis.azureus.util.JSONUtils; public abstract class EngineImpl implements Engine { private static final int DEFAULT_UPDATE_CHECK_SECS = 24*60*60; private static boolean logging_enabled; static{ COConfigurationManager.addAndFireParameterListeners( new String[]{ "Logger.Enabled", }, new ParameterListener() { public void parameterChanged( String parameterName) { logging_enabled = COConfigurationManager.getBooleanParameter( "Logger.Enabled" ); } }); } protected static EngineImpl importFromBEncodedMap( MetaSearchImpl meta_search, Map map ) throws IOException { int type = ((Long)map.get( "type" )).intValue(); if ( type == Engine.ENGINE_TYPE_JSON ){ return( JSONEngine.importFromBEncodedMap( meta_search, map )); }else if ( type == Engine.ENGINE_TYPE_REGEX ){ return( RegexEngine.importFromBEncodedMap( meta_search, map )); }else if ( type == Engine.ENGINE_TYPE_PLUGIN ){ return( PluginEngine.importFromBEncodedMap( meta_search, map )); }else if ( type == Engine.ENGINE_TYPE_RSS ){ return( RSSEngine.importFromBEncodedMap( meta_search, map )); }else{ throw( new IOException( "Unknown engine type " + type )); } } public static Engine importFromJSONString( MetaSearchImpl meta_search, int type, long id, long last_updated, float rank_bias, String name, String content ) throws IOException { JSONObject map = (JSONObject)JSONUtils.decodeJSON( content ); if ( type == Engine.ENGINE_TYPE_JSON ){ return( JSONEngine.importFromJSONString( meta_search, id, last_updated, rank_bias, name, map )); }else if ( type == Engine.ENGINE_TYPE_REGEX ){ return( RegexEngine.importFromJSONString( meta_search, id, last_updated, rank_bias, name, map )); }else if ( type == Engine.ENGINE_TYPE_RSS ){ return( RSSEngine.importFromJSONString( meta_search, id, last_updated, rank_bias, name, map )); }else{ throw( new IOException( "Unknown engine type " + type )); } } // if you extend this with state pertaining to what has been downloaded then // make sure you extend the code in reset(); protected static final String LD_COOKIES = "cookies"; protected static final String LD_ETAG = "etag"; protected static final String LD_LAST_MODIFIED = "last_mod"; protected static final String LD_LAST_UPDATE_CHECK = "last_update_check"; protected static final String LD_UPDATE_CHECK_SECS = "update_check_secs"; protected static final String LD_CREATED_BY_ME = "mine"; protected static final String LD_AUTO_DL_SUPPORTED = "auto_dl_supported"; protected static final String LD_LINK_IS_TORRENT = "link_is_torrent"; private MetaSearchImpl meta_search; private int type; private long id; private long last_updated; private String name; private byte[] uid; private int version; private boolean is_public = true; private int az_version; private int selection_state = SEL_STATE_DESELECTED; private boolean selection_state_recorded = true; private int source = ENGINE_SOURCE_UNKNOWN; private float rank_bias = 1; private float preferred_count = 0; // first mappings used to canonicalise names and map field to same field // typically used for categories (musak->music) private List first_level_mapping = new ArrayList(); // second mappings used to generate derived field values // typically used to derive content_type from category (music->AUDIO) private List second_level_mapping = new ArrayList(); // applicable to non-vuze hosted templates private String update_url; private int update_check_default_secs; private Map user_data; // manual constructor protected EngineImpl( MetaSearchImpl _meta_search, int _type, long _id, long _last_updated, float _rank_bias, String _name ) { meta_search = _meta_search; type = _type; id = _id; last_updated = _last_updated; rank_bias = _rank_bias; name = _name; version = 1; az_version = AZ_VERSION; allocateUID( id ); } // bencoded constructor protected EngineImpl( MetaSearchImpl _meta_search, Map map ) throws IOException { meta_search = _meta_search; type = ((Long)map.get( "type" )).intValue(); Long l_id = (Long)map.get( "id"); id = l_id==null?meta_search.getManager().getLocalTemplateID():l_id.longValue(); last_updated = ImportExportUtils.importLong( map, "last_updated" ); name = ImportExportUtils.importString( map, "name" ); selection_state = (int)ImportExportUtils.importLong( map, "selected", SEL_STATE_DESELECTED ); selection_state_recorded = ImportExportUtils.importBoolean(map,"select_rec", true ); source = (int)ImportExportUtils.importLong( map, "source", ENGINE_SOURCE_UNKNOWN ); rank_bias = ImportExportUtils.importFloat( map, "rank_bias", 1.0f ); preferred_count = ImportExportUtils.importFloat( map, "pref_count", 0.0f ); first_level_mapping = importBEncodedMappings( map, "l1_map" ); second_level_mapping = importBEncodedMappings( map, "l2_map" ); version = (int)ImportExportUtils.importLong( map, "version", 1 ); az_version = (int)ImportExportUtils.importLong( map, "az_version", AZ_VERSION ); if ( az_version > AZ_VERSION ){ throw( new IOException( MessageText.getString("metasearch.template.version.bad", new String[]{ name }))); } uid = (byte[])map.get( "uid" ); if ( uid == null ){ allocateUID( id ); } update_url = ImportExportUtils.importString( map, "update_url" ); update_check_default_secs = (int)ImportExportUtils.importLong( map, "update_url_check_secs", DEFAULT_UPDATE_CHECK_SECS ); } // bencoded export protected void exportToBencodedMap( Map map, boolean generic ) throws IOException { map.put( "type", new Long( type )); ImportExportUtils.exportString( map, "name", name ); map.put( "source", new Long( source )); exportBEncodedMappings( map, "l1_map", first_level_mapping ); exportBEncodedMappings( map, "l2_map", second_level_mapping ); map.put( "version", new Long( version )); map.put( "az_version", new Long( az_version )); ImportExportUtils.exportFloat( map, "rank_bias", rank_bias ); if ( !generic ){ map.put( "id", new Long( id )); map.put( "last_updated", new Long( last_updated )); map.put( "selected", new Long( selection_state )); ImportExportUtils.exportBoolean( map, "select_rec", selection_state_recorded ); ImportExportUtils.exportFloat( map, "pref_count", preferred_count ); map.put( "uid", uid ); } if ( update_url != null ){ ImportExportUtils.exportString( map, "update_url", update_url ); } if ( update_check_default_secs != DEFAULT_UPDATE_CHECK_SECS ){ map.put( "update_url_check_secs", new Long( update_check_default_secs )); } } // json constructor protected EngineImpl( MetaSearchImpl meta_search, int type, long id, long last_updated, float rank_bias, String name, JSONObject map ) throws IOException { this( meta_search, type, id, last_updated, rank_bias, name ); first_level_mapping = importJSONMappings( map, "value_map", true ); second_level_mapping = importJSONMappings( map, "ctype_map", false ); version = (int)ImportExportUtils.importLong( map, "version", 1 ); az_version = (int)ImportExportUtils.importLong( map, "az_version", AZ_VERSION ); if ( az_version > AZ_VERSION ){ throw( new IOException( MessageText.getString( "metasearch.template.version.bad", new String[]{ name }))); } String uid_str = (String)map.get( "uid" ); if ( uid_str == null ){ allocateUID( id ); }else{ uid = Base32.decode( uid_str ); } update_url = ImportExportUtils.importString( map, "update_url" ); update_check_default_secs = (int)ImportExportUtils.importLong( map, "update_url_check_secs", DEFAULT_UPDATE_CHECK_SECS ); } // json export protected void exportToJSONObject( JSONObject res ) throws IOException { exportJSONMappings( res, "value_map", first_level_mapping, true ); exportJSONMappings( res, "ctype_map", second_level_mapping, false ); res.put( "version", new Long( version )); res.put( "az_version", new Long( az_version )); res.put( "uid", Base32.encode( uid )); if ( update_url != null ){ ImportExportUtils.exportJSONString( res, "update_url", update_url ); } res.put( "update_url_check_secs", new Long( update_check_default_secs )); } protected List importJSONMappings( JSONObject map, String str, boolean level_1 ) throws IOException { List result = new ArrayList(); JSONObject field_map = (JSONObject)map.get( str ); if ( field_map != null ){ Iterator it = field_map.entrySet().iterator(); while( it.hasNext()){ Map.Entry entry = (Map.Entry)it.next(); String key = (String)entry.getKey(); List mappings = (List)entry.getValue(); // limited support for the moment: // level one always maps to same field // level two always maps to content type int from_field = vuzeFieldToID( key ); if ( from_field == -1 ){ log( "Unrecognised remapping key '" + key + "'" ); continue; } int to_field = level_1?from_field:FIELD_CONTENT_TYPE; List frs_l = new ArrayList(); for (int i=0;i<mappings.size();i++){ JSONObject mapping = (JSONObject)mappings.get(i); String from_str = URLDecoder.decode((String)mapping.get( level_1?"from_string":"cat_string" ),"UTF-8"); if ( from_str == null ){ log( "'from' value missing in " + mapping ); continue; } from_str = URLDecoder.decode( from_str, "UTF-8" ); String to_str = URLDecoder.decode((String)mapping.get( level_1?"to_string":"media_type" ),"UTF-8"); if ( to_str == null ){ log( "'to' value missing in " + mapping ); continue; } frs_l.add( new FieldRemapping( from_str, to_str )); } FieldRemapping[] frs = (FieldRemapping[])frs_l.toArray( new FieldRemapping[frs_l.size()]); result.add( new FieldRemapper( from_field, to_field, frs )); } } return( result ); } protected void exportJSONMappings( JSONObject res, String str, List l, boolean level_1 ) { JSONObject field_map = new JSONObject(); res.put( str, field_map ); for (int i=0;i<l.size();i++){ FieldRemapper remapper = (FieldRemapper)l.get(i); int from_field = remapper.getInField(); //int to_field = remapper.getOutField(); String from_field_str = vuzeIDToField( from_field ); JSONArray mappings = new JSONArray(); field_map.put( from_field_str, mappings ); FieldRemapping[] frs = remapper.getMappings(); for (int j=0;j<frs.length;j++){ FieldRemapping fr = frs[j]; String from_str = UrlUtils.encode( fr.getMatchString()); String to_str = fr.getReplacement(); JSONObject map = new JSONObject(); mappings.add( map ); map.put( level_1?"from_string":"cat_string", from_str ); map.put( level_1?"to_string":"media_type", to_str ); } } } protected List importBEncodedMappings( Map map, String name ) throws IOException { List result = new ArrayList(); List l = (List)map.get(name); if ( l != null ){ for (int i=0;i<l.size();i++){ Map entry = (Map)l.get(i); int from_field = ((Long)entry.get( "from" )).intValue(); int to_field = ((Long)entry.get( "to" )).intValue(); List l2 = (List)entry.get( "maps" ); FieldRemapping[] mappings = new FieldRemapping[ l2.size() ]; for (int j=0;j<mappings.length;j++){ Map entry2 = (Map)l2.get(j); String from_str = ImportExportUtils.importString( entry2, "from" ); String to_str = ImportExportUtils.importString( entry2, "to" ); mappings[j] = new FieldRemapping( from_str, to_str ); } result.add( new FieldRemapper( from_field, to_field, mappings )); } } return( result ); } protected void exportBEncodedMappings( Map map, String name, List mappings ) throws IOException { List l = new ArrayList(); map.put( name, l ); for ( int i=0;i<mappings.size();i++){ FieldRemapper mapper = (FieldRemapper)mappings.get(i); Map m = new HashMap(); l.add( m ); m.put( "from", new Long( mapper.getInField())); m.put( "to", new Long( mapper.getOutField())); List l2 = new ArrayList(); m.put( "maps", l2 ); FieldRemapping[] frs = mapper.getMappings(); for (int j=0;j<frs.length;j++){ FieldRemapping fr = frs[j]; Map m2 = new HashMap(); l2.add( m2 ); ImportExportUtils.exportString( m2, "from", fr.getMatchString()); ImportExportUtils.exportString( m2, "to", fr.getReplacement()); } } } public String exportToJSONString() throws IOException { JSONObject obj = new JSONObject(); exportToJSONObject( obj ); return( obj.toString()); } public int getAZVersion() { return( az_version ); } public int getVersion() { return( version ); } protected void setVersion( int _v ) { version = _v; } public String getUID() { return( Base32.encode( uid )); } protected void setUID( String str ) { uid = Base32.decode( str ); } protected void allocateUID( long id ) { uid = new byte[10]; if ( id >= 0 && id < Integer.MAX_VALUE ){ // id is a vuze one, derive uid from it as already unique uid[0] = (byte)(id>>24); uid[1] = (byte)(id>>16); uid[2] = (byte)(id>>8); uid[3] = (byte)id; }else{ RandomUtils.nextSecureBytes( uid ); configDirty(); } } public boolean sameLogicAs( Engine other ) { try{ Map m1 = exportToBencodedMap(); Map m2 = other.exportToBencodedMap(); String[] to_remove = { "type", "id", "last_updated", "selected", "select_rec", "source", "rank_bias", "pref_count", "version", "az_version", "uid" }; for (int i=0;i<to_remove.length;i++){ m1.remove( to_remove[i] ); m2.remove( to_remove[i] ); } return( BEncoder.mapsAreIdentical( m1, m2 )); }catch( Throwable e ){ Debug.printStackTrace(e); return( false ); } } public Result[] search( SearchParameter[] params, Map context, int desired_max_matches, int absolute_max_matches, String headers, final ResultListener listener ) throws SearchException { if ( context == null ){ context = new HashMap(); } try{ final Set<Result> results_informed = new HashSet<Result>(); final boolean[] complete_informed = { false }; ResultListener interceptor = new ResultListener() { public void contentReceived( Engine engine, String content ) { listener.contentReceived(engine, content); } public void matchFound( Engine engine, String[] fields ) { listener.matchFound(engine, fields); } public void resultsReceived( Engine engine, Result[] results ) { listener.resultsReceived(engine, results); synchronized( results_informed ){ results_informed.addAll( Arrays.asList( results )); } } public void resultsComplete( Engine engine) { listener.resultsComplete(engine); synchronized( results_informed ){ complete_informed[0] = true; } } public void engineFailed( Engine engine, Throwable cause ) { listener.engineFailed(engine, cause); } public void engineRequiresLogin( Engine engine, Throwable cause ) { listener.engineRequiresLogin(engine, cause); } }; Result[] results = searchAndMap( params, context, desired_max_matches, absolute_max_matches, headers, listener==null?null:interceptor ); if ( listener != null ){ boolean inform_complete; List<Result> inform_result = new ArrayList<Result>(); synchronized( results_informed ){ for ( Result r: results ){ if ( !results_informed.contains( r )){ inform_result.add( r ); } } inform_complete = !complete_informed[0]; } if ( inform_result.size() > 0 ){ listener.resultsReceived( this, inform_result.toArray( new Result[ inform_result.size()] )); } if ( inform_complete ){ listener.resultsComplete( this ); } } return( results ); }catch( Throwable e ){ if ( e instanceof SearchLoginException ){ if ( listener != null ){ listener.engineRequiresLogin(this, e); } throw((SearchLoginException)e); }else if ( e instanceof SearchException ){ if ( listener != null ){ listener.engineFailed( this, e); } throw((SearchException)e); }else{ if ( listener != null ){ listener.engineFailed( this, e); } throw( new SearchException( "Search failed", e )); } } } protected Result[] searchAndMap( SearchParameter[] params, Map context, int desired_max_matches, int absolute_max_matches, String headers, final ResultListener listener ) throws SearchException { // default values context.put( Engine.SC_AZID, ConstantsVuze.AZID ); if ( context.get( Engine.SC_SOURCE ) == null ){ context.put( Engine.SC_SOURCE, "search" ); } Result[] results = searchSupport( params, context, desired_max_matches, absolute_max_matches, headers, new ResultListener() { public void contentReceived( Engine engine, String content ) { if ( listener != null ){ listener.contentReceived(engine, content); } } public void matchFound( Engine engine, String[] fields ) { if ( listener != null ){ listener.matchFound(engine, fields); } } public void resultsReceived( Engine engine, Result[] results) { if ( listener != null ){ listener.resultsReceived(engine, mapResults( results )); } } public void resultsComplete( Engine engine ) { if ( listener != null ){ listener.resultsComplete(engine); } } public void engineFailed( Engine engine, Throwable cause ) { log( "Search failed", cause ); if ( listener != null ){ listener.engineFailed(engine, cause); } } public void engineRequiresLogin( Engine engine, Throwable cause ) { log( "Search requires login", cause ); if ( listener != null ){ listener.engineRequiresLogin(engine, cause); } } }); return( mapResults( results )); } protected Result[] mapResults( Result[] results ) { for (int i=0;i<results.length;i++){ Result result = results[i]; for (int j=0;j<first_level_mapping.size();j++){ FieldRemapper mapper = (FieldRemapper)first_level_mapping.get(j); mapper.remap( result ); } for (int j=0;j<second_level_mapping.size();j++){ FieldRemapper mapper = (FieldRemapper)second_level_mapping.get(j); mapper.remap( result ); } } return( results ); } protected abstract Result[] searchSupport( SearchParameter[] params, Map searchContext, int desired_max_matches, int absolute_max_matches, String headers, ResultListener listener ) throws SearchException; public void delete() { meta_search.removeEngine( this ); } protected MetaSearchImpl getMetaSearch() { return( meta_search ); } protected int vuzeFieldToID( String field ) { for (int i=0;i<FIELD_NAMES.length;i++){ if ( field.equalsIgnoreCase( FIELD_NAMES[i] )){ return( FIELD_IDS[i]); } } return( -1 ); } protected String vuzeIDToField( int id ) { for (int i=0;i<FIELD_IDS.length;i++){ if ( id == FIELD_IDS[i] ){ return( FIELD_NAMES[i]); } } return( null ); } public int getType() { return( type ); } protected void setId( long _id ) { id = _id; } public long getId() { return id; } public long getLastUpdated() { return( last_updated ); } public String getName() { return( name ); } protected void setName( String n ) { name = n; } public boolean isActive() { return( getSelectionState() != SEL_STATE_DESELECTED ); } public boolean isPublic() { return( is_public ); } protected void setPublic( boolean p ) { is_public = p; } public int getSelectionState() { return( selection_state ); } public void setSelectionState( int state ) { if ( state != selection_state ){ // only record transitions to or from manual selection for non-local templates if ( getSource() == ENGINE_SOURCE_VUZE ){ if ( state == SEL_STATE_MANUAL_SELECTED || selection_state == SEL_STATE_MANUAL_SELECTED ){ selection_state_recorded = false; checkSelectionStateRecorded(); } } selection_state = state; configDirty(); } } public boolean isAuthenticated() { return( false ); } public void recordSelectionState() { selection_state_recorded = false; checkSelectionStateRecorded(); } public void checkSelectionStateRecorded() { if ( !selection_state_recorded ){ try{ boolean selected = selection_state != SEL_STATE_DESELECTED; log( "Marking template id " + getId() + " as selected=" + selected ); PlatformMetaSearchMessenger.setTemplatetSelected( meta_search.getManager().getExtensionKey(), getId(), ConstantsVuze.AZID, selected); selection_state_recorded = true; }catch( Throwable e ){ log( "Failed to record selection state", e ); } } } public int getSource() { return( source ); } public void setSource( int _source ) { if ( source != _source ){ source = _source; configDirty(); } } public float getRankBias() { return( rank_bias ); } public void setRankBias( float _rank_bias ) { if ( rank_bias != _rank_bias ){ rank_bias = _rank_bias; configDirty(); } } public void setPreferredDelta( float delta ) { float new_pref = preferred_count + delta; new_pref = Math.max( 0, new_pref ); new_pref = Math.min( 10, new_pref ); if ( new_pref != preferred_count ){ preferred_count = new_pref; configDirty(); } } public float getPreferredWeighting() { return( preferred_count ); } public float applyRankBias( float _rank ) { float rank = _rank*rank_bias; rank *= (1 + 0.025 * preferred_count ); rank = Math.min( rank, 1.0f ); rank = Math.max( rank, 0.0f ); // System.out.println( getName() + " (" + rank_bias+"/"+preferred_count + "): " + _rank + " -> " + rank ); return( rank ); } public boolean isMine() { return( getLocalBoolean( LD_CREATED_BY_ME, false )); } public void setMine( boolean mine ) { setLocalBoolean( LD_CREATED_BY_ME, mine ); } protected String getUpdateURL() { return( update_url ); } protected void setUpdateURL( String url ) { update_url = url; } protected int getUpdateCheckSecs() { long l = getLocalLong( LD_UPDATE_CHECK_SECS, 0 ); if ( l != 0 ){ return((int)l); } return( update_check_default_secs ); } protected void setDefaultUpdateCheckSecs( int secs ) { update_check_default_secs = secs; } protected void setLocalUpdateCheckSecs( int secs ) { setLocalLong( LD_UPDATE_CHECK_SECS, secs ); } protected long getLastUpdateCheck() { return( getLocalLong( LD_LAST_UPDATE_CHECK, 0 )); } protected void setLastUpdateCheck( long when ) { setLocalLong( LD_LAST_UPDATE_CHECK, when ); } public int getAutoDownloadSupported() { // default impl based on availability of fields that permit auto-dl // overridden in RSS engine ( for example ) to be based on explicit // channel tag boolean ok = supportsField( Engine.FIELD_TORRENTLINK ) || supportsField( Engine.FIELD_DOWNLOADBTNLINK ); return( ok?AUTO_DL_SUPPORTED_YES:AUTO_DL_SUPPORTED_NO ); } protected void configDirty() { if ( meta_search != null ){ meta_search.configDirty(); } } public void addPotentialAssociation( String key ) { meta_search.addPotentialAssociation( this, key ); } public void exportToVuzeFile( File target ) throws IOException { VuzeFile vf = VuzeFileHandler.getSingleton().create(); vf.addComponent( VuzeFileComponent.COMP_TYPE_METASEARCH_TEMPLATE, exportToBencodedMap()); vf.write( target ); } public VuzeFile exportToVuzeFile() throws IOException { return( exportToVuzeFile( false )); } public VuzeFile exportToVuzeFile( boolean generic ) throws IOException { VuzeFile vf = VuzeFileHandler.getSingleton().create(); vf.addComponent( VuzeFileComponent.COMP_TYPE_METASEARCH_TEMPLATE, exportToBencodedMap( generic )); return( vf ); } private String getLocalKey() { return( "metasearch.engine." + id + ".local" ); } public void reset() { synchronized( this ){ Map map = COConfigurationManager.getMapParameter( getLocalKey(), new HashMap()); map.remove( LD_COOKIES ); map.remove( LD_ETAG ); map.remove( LD_LAST_MODIFIED ); COConfigurationManager.setParameter( getLocalKey(), map ); } } protected void setLocalString( String key, String value ) { synchronized( this ){ String existing = getLocalString( key ); if ( existing != null && value != null && existing.equals( value )){ return; } Map map = COConfigurationManager.getMapParameter( getLocalKey(), new HashMap()); try{ ImportExportUtils.exportString(map, key, value); COConfigurationManager.setParameter( getLocalKey(), map ); }catch( Throwable e ){ Debug.printStackTrace( e ); } } } protected String getLocalString( String key ) { synchronized( this ){ Map map = COConfigurationManager.getMapParameter( getLocalKey(), new HashMap()); try{ return( ImportExportUtils.importString( map, key )); }catch( Throwable e ){ Debug.printStackTrace( e ); return( null ); } } } protected void setLocalBoolean( String key, boolean value ) { setLocalLong( key, value?1:0 ); } protected boolean getLocalBoolean( String key, boolean def ) { return( getLocalLong( key, def?1:0 ) == 1 ); } protected void setLocalLong( String key, long value ) { synchronized( this ){ long existing = getLocalLong( key, 0 ); if ( existing == value ){ return; } Map map = COConfigurationManager.getMapParameter( getLocalKey(), new HashMap()); try{ map.put( key, new Long( value)); COConfigurationManager.setParameter( getLocalKey(), map ); }catch( Throwable e ){ Debug.printStackTrace( e ); } } } protected long getLocalLong( String key, long def ) { synchronized( this ){ Map map = COConfigurationManager.getMapParameter( getLocalKey(), new HashMap()); try{ return( ImportExportUtils.importLong( map, key, def )); }catch( Throwable e ){ Debug.printStackTrace( e ); return( def ); } } } protected void setUserData( Object key, Object value ) { synchronized( this ){ if ( user_data == null ){ if ( key == null ){ return; } user_data = new HashMap(4); } if ( key == null ){ user_data.remove( key ); if ( user_data.size() == 0 ){ user_data = null; } }else{ user_data.put( key, value ); } } } protected Object getUserData( Object key ) { synchronized( this ){ if ( user_data == null ){ return( null ); } return( user_data.get( key )); } } protected File getDebugFile() { if ( logging_enabled ){ return( new File( AEDiagnostics.getLogDir(), "MetaSearch_Engine_" + getId() + ".txt" )); }else{ return( null ); } } protected synchronized void debugStart() { File f = getDebugFile(); if ( f != null ){ f.delete(); } } protected synchronized void debugLog( String str ) { File f = getDebugFile(); if ( f != null ){ PrintWriter pw = null; try{ pw = new PrintWriter(new FileWriter( f, true )); pw.println( str ); }catch( Throwable e ){ }finally{ if ( pw != null ){ pw.close(); } } } } protected void log( String str ) { if ( meta_search != null ){ meta_search.log( "Engine " + getId() + ": " + str ); } } protected void log( String str, Throwable e ) { if ( meta_search != null ){ meta_search.log( "Engine " + getId() + ": " + str, e ); } } public String getString() { return( "id=" + getId() + ", name=" + getName() + ", source=" + ENGINE_SOURCE_STRS[getSource()] + ", selected=" + SEL_STATE_STRINGS[getSelectionState()] + ", rb=" + rank_bias + ", pref=" + preferred_count ); } public String getString( boolean full ) { return( getString()); } }