<commit_before>/*
 * Copyright (C) 2012 the diamond:dogs|group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package at.diamonddogs.service.net;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.RecoverySystem.ProgressListener;
import at.diamonddogs.data.adapter.ReplyAdapter;
import at.diamonddogs.data.dataobjects.WebRequest;
import at.diamonddogs.exception.ServiceException;
import at.diamonddogs.net.WebClient.DownloadProgressListener;
import at.diamonddogs.service.net.HttpService.HttpServiceBinder;
import at.diamonddogs.service.net.HttpService.WebRequestReturnContainer;
import at.diamonddogs.service.processor.DataProcessor;
import at.diamonddogs.service.processor.ServiceProcessor;
import at.diamonddogs.service.processor.SynchronousProcessor;

/**
 * The {@link HttpServiceAssister} can be used to issue {@link WebRequest}s at
 * any given time, without having to worry if a service binding to
 * {@link HttpService} exists. {@link HttpServiceAssister} supports both,
 * asynchronous and synchronous {@link WebRequest}s. If the {@link HttpService}
 * has not been bound yet, asynchronous {@link WebRequest}s will be appended to
 * a queue, which will be processed once a connection to {@link HttpService} has
 * been established. Synchronous {@link WebRequest}s will cause
 * {@link HttpServiceAssister} to wait for a maximum of
 * {@link HttpServiceAssister#SYNC_REQUEST_BINDING_TIMEOUT} milliseconds until
 * {@link Service} binding.
 */
public class HttpServiceAssister {

	private static final Logger LOGGER = LoggerFactory.getLogger(HttpServiceAssister.class.getSimpleName());

	/**
	 * Service binding timeout for synchronous {@link WebRequest}s.
	 */
	private static final int SYNC_REQUEST_BINDING_TIMEOUT = 2000;

	/**
	 * A {@link Context} object that will be used for all Android specific
	 * calls, such as {@link Service} binding.
	 */
	private Context context;

	/**
	 * The instance of {@link HttpService} that is used for issuing
	 * {@link WebRequest}s.
	 */
	private HttpService httpService;

	/**
	 * Contains the "active" {@link ServiceConnection} to {@link HttpService}.
	 * Can be null if {@link HttpService} was unbound.
	 */
	private ServiceConnection activeServiceConnection;

	/**
	 * The template {@link ServiceConnection} used as
	 * {@link HttpServiceAssister#activeServiceConnection}, can be exchanged
	 * with a custom implementation.
	 */
	private ServiceConnection standardServiceConnection;

	/**
	 * This {@link Queue} holds all asynchronous {@link WebRequest}s that need
	 * to be processed once a connection to {@link HttpService} has been
	 * established.
	 */
	private final Queue<WebRequestInformation> pendingWebRequests;

	/**
	 * This flag is set by {@link HttpServiceAssister#savlyUnbindService()}. It
	 * ensures that pending {@link WebRequest} will be executed prior to
	 * unbinding the {@link HttpService}
	 */
	private final AtomicBoolean unbindServiceAfterWebRequestExecution = new AtomicBoolean(false);

	/**
	 * This flag indicates if synchronous {@link WebRequest}s can currently be
	 * processed. Is false when {@link HttpServiceAssister#bindService()} has
	 * not been called or if {@link HttpServiceAssister#unbindService()} has
	 * been called.
	 */
	private final AtomicBoolean synchronousWebRequestPossible = new AtomicBoolean(false);

	/**
	 * This monitor {@link Object} is used to wait for a connection to
	 * {@link HttpService} when running a synchronous {@link WebRequest}.
	 */
	private final Object monitor = new Object();

	/**
	 * Default constructor
	 * 
	 * @param context
	 *            a {@link Context} object.
	 */
	public HttpServiceAssister(Context context) {
		this.context = context;
		this.pendingWebRequests = new LinkedList<WebRequestInformation>();
	}

	/**
	 * Starts {@link HttpService} binding process. Will use
	 * {@link HttpServiceAssister#standardServiceConnection} if no custom
	 * {@link ServiceConnection} has been supplied.
	 * 
	 * @return <code>true</code> if the connection to {@link HttpService} could
	 *         be established, <code>false</code> if the service has already
	 *         been bound or if binding is impossible.
	 */
	public boolean bindService() {
		if (standardServiceConnection == null) {
			standardServiceConnection = new HttpServiceAssisterConnection();
		}
		if (activeServiceConnection == null) {
			synchronousWebRequestPossible.set(true);
			return context.bindService(new Intent(context, HttpService.class), activeServiceConnection = standardServiceConnection,
					Context.BIND_AUTO_CREATE);
		} else {
			return false;
		}
	}

	/**
	 * Unbinds the {@link HttpService}. All pending {@link WebRequest} will be
	 * discarded!
	 * 
	 * @return <code>true</code> if {@link HttpService} was bound and therefore
	 *         successfully unbound, <code>false</code> otherwise.
	 */
	public boolean unbindService() {
		if (activeServiceConnection != null) {
			synchronousWebRequestPossible.set(false);
			unbindServiceAfterWebRequestExecution.set(false);
			context.unbindService(activeServiceConnection);
			activeServiceConnection = null;
			httpService = null;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unbinds the {@link HttpService}. Pending {@link WebRequest}s will be
	 * executed before unbinding.
	 * 
	 * @return
	 */
	public boolean safelyUnbindService() {
		if (activeServiceConnection != null) {
			if (hasPendingAsyncWebRequests()) {
				unbindServiceAfterWebRequestExecution.set(true);
			} else {
				synchronousWebRequestPossible.set(false);
				context.unbindService(activeServiceConnection);
				activeServiceConnection = null;
				httpService = null;
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Runs a {@link WebRequest} asynchronously
	 * 
	 * @param callback
	 *            the {@link Handler.Callback} that will be informed once the
	 *            {@link WebRequest} has been completed
	 * @param webRequest
	 *            the {@link WebRequest} to run
	 * @param serviceProcessor
	 *            the {@link ServiceProcessor} that should be used to process
	 *            the {@link WebRequest}
	 */
	public void runWebRequest(Handler.Callback callback, WebRequest webRequest, ServiceProcessor<?> serviceProcessor) {
		runWebRequest(new Handler(callback), webRequest, serviceProcessor, null);
	}
<commit_msg>[FIX] made synchronousWebRequestPossible() determination simpler<commit_after>/*
 * Copyright (C) 2012 the diamond:dogs|group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package at.diamonddogs.service.net;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.RecoverySystem.ProgressListener;
import at.diamonddogs.data.adapter.ReplyAdapter;
import at.diamonddogs.data.dataobjects.WebRequest;
import at.diamonddogs.exception.ServiceException;
import at.diamonddogs.net.WebClient.DownloadProgressListener;
import at.diamonddogs.service.net.HttpService.HttpServiceBinder;
import at.diamonddogs.service.net.HttpService.WebRequestReturnContainer;
import at.diamonddogs.service.processor.DataProcessor;
import at.diamonddogs.service.processor.ServiceProcessor;
import at.diamonddogs.service.processor.SynchronousProcessor;

/**
 * The {@link HttpServiceAssister} can be used to issue {@link WebRequest}s at
 * any given time, without having to worry if a service binding to
 * {@link HttpService} exists. {@link HttpServiceAssister} supports both,
 * asynchronous and synchronous {@link WebRequest}s. If the {@link HttpService}
 * has not been bound yet, asynchronous {@link WebRequest}s will be appended to
 * a queue, which will be processed once a connection to {@link HttpService} has
 * been established. Synchronous {@link WebRequest}s will cause
 * {@link HttpServiceAssister} to wait for a maximum of
 * {@link HttpServiceAssister#SYNC_REQUEST_BINDING_TIMEOUT} milliseconds until
 * {@link Service} binding.
 */
public class HttpServiceAssister {

	private static final Logger LOGGER = LoggerFactory.getLogger(HttpServiceAssister.class.getSimpleName());

	/**
	 * Service binding timeout for synchronous {@link WebRequest}s.
	 */
	private static final int SYNC_REQUEST_BINDING_TIMEOUT = 2000;

	/**
	 * A {@link Context} object that will be used for all Android specific
	 * calls, such as {@link Service} binding.
	 */
	private Context context;

	/**
	 * The instance of {@link HttpService} that is used for issuing
	 * {@link WebRequest}s.
	 */
	private HttpService httpService;

	/**
	 * Contains the "active" {@link ServiceConnection} to {@link HttpService}.
	 * Can be null if {@link HttpService} was unbound.
	 */
	private ServiceConnection activeServiceConnection;

	/**
	 * The template {@link ServiceConnection} used as
	 * {@link HttpServiceAssister#activeServiceConnection}, can be exchanged
	 * with a custom implementation.
	 */
	private ServiceConnection standardServiceConnection;

	/**
	 * This {@link Queue} holds all asynchronous {@link WebRequest}s that need
	 * to be processed once a connection to {@link HttpService} has been
	 * established.
	 */
	private final Queue<WebRequestInformation> pendingWebRequests;

	/**
	 * This flag is set by {@link HttpServiceAssister#savlyUnbindService()}. It
	 * ensures that pending {@link WebRequest} will be executed prior to
	 * unbinding the {@link HttpService}
	 */
	private final AtomicBoolean unbindServiceAfterWebRequestExecution = new AtomicBoolean(false);

	/**
	 * This flag indicates if synchronous {@link WebRequest}s can currently be
	 * processed. Is false when {@link HttpServiceAssister#bindService()} has
	 * not been called or if {@link HttpServiceAssister#unbindService()} has
	 * been called.
	 */
	private final AtomicBoolean synchronousWebRequestPossible = new AtomicBoolean(false);

	/**
	 * This monitor {@link Object} is used to wait for a connection to
	 * {@link HttpService} when running a synchronous {@link WebRequest}.
	 */
	private final Object monitor = new Object();

	/**
	 * Default constructor
	 * 
	 * @param context
	 *            a {@link Context} object.
	 */
	public HttpServiceAssister(Context context) {
		this.context = context;
		this.pendingWebRequests = new LinkedList<WebRequestInformation>();
	}

	/**
	 * Starts {@link HttpService} binding process. Will use
	 * {@link HttpServiceAssister#standardServiceConnection} if no custom
	 * {@link ServiceConnection} has been supplied.
	 * 
	 * @return <code>true</code> if the connection to {@link HttpService} could
	 *         be established, <code>false</code> if the service has already
	 *         been bound or if binding is impossible.
	 */
	public boolean bindService() {
		synchronousWebRequestPossible.set(true);
		if (standardServiceConnection == null) {
			standardServiceConnection = new HttpServiceAssisterConnection();
		}
		if (activeServiceConnection == null) {
			return context.bindService(new Intent(context, HttpService.class), activeServiceConnection = standardServiceConnection,
					Context.BIND_AUTO_CREATE);
		} else {
			return false;
		}
	}

	/**
	 * Unbinds the {@link HttpService}. All pending {@link WebRequest} will be
	 * discarded!
	 * 
	 * @return <code>true</code> if {@link HttpService} was bound and therefore
	 *         successfully unbound, <code>false</code> otherwise.
	 */
	public boolean unbindService() {
		synchronousWebRequestPossible.set(false);
		if (activeServiceConnection != null) {
			unbindServiceAfterWebRequestExecution.set(false);
			context.unbindService(activeServiceConnection);
			activeServiceConnection = null;
			httpService = null;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Unbinds the {@link HttpService}. Pending {@link WebRequest}s will be
	 * executed before unbinding.
	 * 
	 * @return
	 */
	public boolean safelyUnbindService() {
		synchronousWebRequestPossible.set(false);
		if (activeServiceConnection != null) {
			if (hasPendingAsyncWebRequests()) {
				unbindServiceAfterWebRequestExecution.set(true);
			} else {
				context.unbindService(activeServiceConnection);
				activeServiceConnection = null;
				httpService = null;
			}
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Runs a {@link WebRequest} asynchronously
	 * 
	 * @param callback
	 *            the {@link Handler.Callback} that will be informed once the
	 *            {@link WebRequest} has been completed
	 * @param webRequest
	 *            the {@link WebRequest} to run
	 * @param serviceProcessor
	 *            the {@link ServiceProcessor} that should be used to process
	 *            the {@link WebRequest}
	 */
	public void runWebRequest(Handler.Callback callback, WebRequest webRequest, ServiceProcessor<?> serviceProcessor) {
		runWebRequest(new Handler(callback), webRequest, serviceProcessor, null);
	}

{'fraction_non_alphanumeric': 0.09353067889653255, 'fraction_numerical': 0.0019456604822458482, 'mean_word_length': 4.308742161563998, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2652202', 'n_tokens_mistral': 4160, 'n_tokens_neox': 3772, 'n_words': 1274}