All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.code.facebookapi.BasicClient Maven / Gradle / Ivy

The newest version!
package com.google.code.facebookapi;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONArray;
import org.json.JSONException;

/**
 * Basic client taking care of rest call mechanics (signing, etc) to facebook. Little api knowledge, no response interpretation is planned.
 */
public class BasicClient {

	protected static Log log = LogFactory.getLog( BasicClient.class );

	protected URL serverUrl;
	protected URL serverUrlHttps;
	private CommunicationStrategy communicationStrategy;

	protected final String apiKey;
	protected final String secret;
	protected boolean sessionSecret;

	protected boolean batchMode;
	protected List queries;
	protected String permissionsApiKey;

	public boolean isBatchMode() {
		return batchMode;
	}

	protected List getQueries() {
		return queries;
	}

	protected BasicClient( String apiKey, String secret, boolean sessionSecret ) {
		this( null, null, apiKey, secret, sessionSecret, new DefaultCommunicationStrategy() );
	}

	protected BasicClient( URL serverUrl, URL serverUrlHttps, String apiKey, String secret, boolean sessionSecret, CommunicationStrategy communicationStrategy ) {
		this.apiKey = apiKey;
		this.secret = secret;
		this.sessionSecret = sessionSecret || secret.endsWith( "__" );
		this.serverUrl = ( null != serverUrl ) ? serverUrl : FacebookApiUrls.getDefaultServerUrl();
		this.serverUrlHttps = ( null != serverUrlHttps ) ? serverUrlHttps : FacebookApiUrls.getDefaultHttpsServerUrl();

		this.communicationStrategy = communicationStrategy;
		this.batchMode = false;
		this.queries = null;
	}

	public String getApiKey() {
		return apiKey;
	}

	public String getSecret() {
		return secret;
	}

	public boolean isSessionSecret() {
		return sessionSecret;
	}

	public void beginPermissionsMode( String apiKey ) {
		this.permissionsApiKey = apiKey;
	}

	public void endPermissionsMode() {
		this.permissionsApiKey = null;
	}

	public void setServerUrl( String newUrl ) {
		String base = newUrl;
		if ( base.startsWith( "http" ) ) {
			base = base.substring( base.indexOf( "://" ) + 3 );
		}
		try {
			String url = "http://" + base;
			serverUrl = new URL( url );
		}
		catch ( MalformedURLException ex ) {
			throw BasicClientHelper.runtimeException( ex );
		}
	}

	public void setServerUrlHttps( String newUrl ) {
		String base = newUrl;
		if ( base.startsWith( "https" ) ) {
			base = base.substring( base.indexOf( "://" ) + 3 );
		}
		try {
			String url = "https://" + base;
			serverUrlHttps = new URL( url );
		}
		catch ( MalformedURLException ex ) {
			throw BasicClientHelper.runtimeException( ex );
		}
	}

	public String callMethod( String responseFormat, IFacebookMethod method, String sessionKey, Pair... paramPairs ) throws FacebookException {
		return callMethod( responseFormat, method, sessionKey, Arrays.asList( paramPairs ), null, null );
	}

	public String callMethod( String responseFormat, IFacebookMethod method, String sessionKey, Collection> paramPairs )
			throws FacebookException {
		return callMethod( responseFormat, method, sessionKey, paramPairs, null, null );
	}

	public String callMethod( String responseFormat, IFacebookMethod method, Pair... paramPairs ) throws FacebookException {
		return callMethod( responseFormat, method, null, Arrays.asList( paramPairs ), null, null );
	}

	public String callMethod( String responseFormat, IFacebookMethod method, Collection> paramPairs ) throws FacebookException {
		return callMethod( responseFormat, method, null, paramPairs, null, null );
	}

	protected SortedMap prepareRequestParams( String responseFormat, IFacebookMethod method, String sessionKey,
			Collection> paramPairs ) throws FacebookException {
		SortedMap params = new TreeMap();

		for ( Pair p : paramPairs ) {
			final String key = p.first;
			CharSequence oldVal = params.put( key, BasicClientHelper.toString( p.second ) );
			if ( oldVal != null ) {
				log.warn( String.format( "For parameter %s, overwrote old value %s with new value %s.", key, oldVal, p.second ) );
			}
		}

		if ( permissionsApiKey != null ) {
			params.put( "call_as_apikey", permissionsApiKey );
		}

		params.put( "v", IFacebookRestClient.TARGET_API_VERSION );
		params.put( "call_id", Long.toString( System.currentTimeMillis() ) );
		params.put( "method", method.methodName() );
		if ( responseFormat != null ) {
			params.put( "format", responseFormat );
		}

		params.put( "api_key", apiKey );
		boolean includeSession = sessionKey != null;
		if ( includeSession ) {
			params.put( "session_key", sessionKey );
		}

		params.remove( "sig" );
		if ( sessionSecret ) {
			params.put( "ss", "1" );
		}
		String signature = FacebookSignatureUtil.generateSignature( params, secret );
		params.put( "sig", signature );

		return params;
	}

	public String callMethod( String responseFormat, IFacebookMethod method, String sessionKey, Collection> paramPairs, String fileName,
			InputStream fileStream ) throws FacebookException {
		SortedMap params = prepareRequestParams( responseFormat, method, sessionKey, paramPairs );
		final boolean fileCall = fileName != null || fileStream != null;
		if ( batchMode ) {
			if ( fileCall ) {
				throw new FacebookException( ErrorCode.GEN_INVALID_PARAMETER, "File upload API calls cannot be batched:  " + method.methodName() );
			}
			// if we are running in batch mode, don't actually execute the query now, just add it to the list
			boolean addToBatch = true;
			// FIXME what the heck is going on here??
			if ( method.methodName().equals( FacebookMethod.USERS_GET_LOGGED_IN_USER.methodName() ) ) {
				Exception trace = new Exception();
				StackTraceElement[] traceElems = trace.getStackTrace();
				int index = 0;
				for ( StackTraceElement elem : traceElems ) {
					if ( elem.getMethodName().indexOf( "_" ) != -1 ) {
						StackTraceElement caller = traceElems[index + 1];
						final boolean calledFromSelf = caller.getClassName().equals( BasicClient.class.getName() );
						final boolean calledFromAuth = caller.getMethodName().startsWith( "auth_" );
						if ( calledFromSelf && !calledFromAuth ) {
							addToBatch = false;
						}
						break;
					}
					index++ ;
				}
			}
			if ( addToBatch ) {
				queries.add( new BatchQuery( method, params ) );
				// should return null be here or below
				// return null;
			}
			return null;
		}

		try {
			// FIXME when to use https?
			// when called from desktop, some methods require https
			boolean doHttps = FacebookMethod.AUTH_GET_SESSION.equals( method ) && "true".equals( params.get( "generate_session_secret" ) );
			URL url = ( doHttps ) ? serverUrlHttps : serverUrl;
			if ( fileCall ) {
				if ( log.isDebugEnabled() ) {
					log.debug( method.methodName() + ": POST-FILE: " + url.toString() + ": " + params );
				}
				return communicationStrategy.postRequest( url, params, fileName, fileStream );
			} else {
				if ( log.isDebugEnabled() ) {
					log.debug( method.methodName() + ": POST: " + url.toString() + ": " + params );
				}
				return communicationStrategy.postRequest( url, params );
			}
		}
		catch ( IOException ex ) {
			throw BasicClientHelper.runtimeException( ex );
		}
	}

	public void beginBatch() {
		batchMode = true;
		queries = new ArrayList();
	}

	/**
	 * Returns a list of String raw responses which will be further broken down by the adapters into the actual individual responses. One string is returned per 20
	 * methods in the batch.
	 */
	public List executeBatch( boolean serial ) throws FacebookException {
		batchMode = false;
		final List q = queries;
		queries = null;

		final int BATCH_LIMIT = 20;
		final List result = new ArrayList();
		List buffer = new ArrayList( BATCH_LIMIT );
		while ( !q.isEmpty() ) {
			buffer.add( q.remove( 0 ) );
			boolean batchFull = buffer.size() >= BATCH_LIMIT;
			if ( batchFull || ( q.isEmpty() ) ) {
				List batchRawResponse = batch_run( encodeMethods( buffer ), serial );
				result.addAll( batchRawResponse );
				if ( batchFull ) {
					buffer = new ArrayList( BATCH_LIMIT );
				}
			}
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	protected List batch_run( String methods, boolean serial ) throws FacebookException {
		final String call = callMethod( "json", FacebookMethod.BATCH_RUN, null, Arrays.asList( Pairs.newPair( "method_feed", methods ), Pairs.newPair10( "serial_only",
				serial ) ), null, null );
		try {
			JSONArray arr = new JSONArray( call );
			List out = new ArrayList();
			int l = arr.length();
			for ( int i = 0; i < l; i++ ) {
				out.add( arr.getString( i ) );
			}
			return out;
		}
		catch ( JSONException ex ) {
			throw BasicClientHelper.runtimeException( ex );
		}
	}

	protected static String encodeMethods( List queryList ) throws FacebookException {
		JSONArray result = new JSONArray();
		for ( BatchQuery query : queryList ) {
			if ( query.getMethod().takesFile() ) {
				throw new FacebookException( ErrorCode.GEN_INVALID_PARAMETER, "File upload API calls cannot be batched:  " + query.getMethod().methodName() );
			}
			result.put( BasicClientHelper.delimit( query.getParams().entrySet(), "&", "=", true ) );
		}
		return result.toString();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy