/**
 * Copyright (c) 2000-2017 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * pSubscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.portal.kernel.concurrent;

import com.liferay.portal.kernel.dao.shard.ShardUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ClassUtil;

import java.util.Arrays;
import java.util.List;

/**
 * @author Michael C. Han
 */
public abstract class ThrowableAwareRunnable implements Runnable {

	public ThrowableAwareRunnable(String shardName) {
		_shardName = shardName;
	}

	public Throwable getThrowable() {
		return _throwable;
	}

	public boolean hasException() {
		return (_throwable != null);
	}

	@Override
	public void run() {
		long start = System.currentTimeMillis();

		String currentShardName = ShardUtil.getCurrentShardName();

		List<String> shardNames = Arrays.asList(
			ShardUtil.getAvailableShardNames());

		try {
			if (!shardNames.isEmpty()) {
				if (shardNames.contains(_shardName)) {
					ShardUtil.pushCompanyService(_shardName);

					ShardUtil.setTargetSource(_shardName);
				}
				else {
					throw new PortalException("Invalid shard name");
				}
			}

			if (_log.isInfoEnabled()) {
				_log.info(
					"Processing runnable " + ClassUtil.getClassName(this));
			}

			doRun();
		}
		catch (Exception e) {
			_log.error("Unable to process runnable: " + e.getMessage());

			_throwable = e;
		}
		finally {
			if (!shardNames.isEmpty() && shardNames.contains(_shardName)) {
				ShardUtil.setTargetSource(currentShardName);

				ShardUtil.popCompanyService();
			}

			if (_log.isInfoEnabled()) {
				_log.info(
					"Completed processing runnable " +
						ClassUtil.getClassName(this) + " in " +
							(System.currentTimeMillis() - start) + "ms");
			}
		}
	}

	protected abstract void doRun() throws Exception;

	private static Log _log = LogFactoryUtil.getLog(
		ThrowableAwareRunnable.class);

	private String _shardName;
	private Throwable _throwable;

}