/*
* Copyright 2013 the original author or authors.
*
* 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 org.sbq.batch.mains;
import org.sbq.batch.domain.User;
import org.sbq.batch.configurations.ActivityEmulatorConfiguration;
import org.sbq.batch.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author ilya40umov
*/
public class ActivityEmulator
{
private final BlockingQueue<Runnable> blockingQueue;
private final ExecutorService executor;
private final ApplicationContext appCtx;
private final UserService userService;
private final Map<String, AtomicBoolean> userStatusByLogin;
private ActivityEmulator()
{
super();
blockingQueue = new LinkedBlockingQueue<Runnable>();
executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, blockingQueue);
appCtx = new AnnotationConfigApplicationContext(ActivityEmulatorConfiguration.class);
userService = appCtx.getBean(UserService.class);
Map<String, AtomicBoolean> writableUserStatusByLogin = new HashMap<String, AtomicBoolean>();
for (User user : userService.findAllUsers())
{
writableUserStatusByLogin.put(user.getLogin(), new AtomicBoolean(false));
}
userStatusByLogin = Collections.unmodifiableMap(writableUserStatusByLogin);
}
public static void main(String[] vars) throws IOException
{
System.out.println("ActivityEmulator - STARTED.");
ActivityEmulator activityEmulator = new ActivityEmulator();
activityEmulator.begin();
System.out.println("Enter your command: >");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String command = null;
while (!"stop".equals(command = in.readLine()))
{
if ("status".equals(command))
{
List<String> onlineUsers = new LinkedList<String>();
for (Map.Entry<String, AtomicBoolean> entry : activityEmulator.getUserStatusByLogin().entrySet())
{
if (entry.getValue().get())
{
onlineUsers.add(entry.getKey());
}
}
System.out.println("Users online: " + Arrays.toString(onlineUsers.toArray()));
System.out.println("Number of cycles left: " + activityEmulator.getBlockingQueue().size());
}
System.out.println("Enter your command: >");
}
activityEmulator.stop();
System.out.println("ActivityEmulator - STOPPED.");
}
private void begin()
{
for (int i = 0; i < 100000; i++)
{
executor.execute(new UserEmulator());
}
}
private void stop()
{
executor.shutdownNow();
}
public BlockingQueue<Runnable> getBlockingQueue()
{
return blockingQueue;
}
public ExecutorService getExecutor()
{
return executor;
}
public Map<String, AtomicBoolean> getUserStatusByLogin()
{
return userStatusByLogin;
}
private final class UserEmulator implements Runnable
{
private final Random rnd = new Random();
@Override
public void run()
{
String login = acquireRandomOfflineUser();
try
{
String sessionId = userService.login(login);
sleep(rnd.nextInt(10) * 100L);
for (int i = 0, n = rnd.nextInt(5); i < n; i++)
{
switch (rnd.nextInt(4))
{
case 0:
userService.goChatting(sessionId);
break;
case 1:
userService.goDancing(sessionId);
break;
case 2:
userService.goIdle(sessionId);
break;
case 3:
userService.goWalking(sessionId);
break;
}
sleep(rnd.nextInt(10) * 100L);
}
sleep(rnd.nextInt(10) * 100L);
userService.logout(sessionId);
} finally
{
releaseUser(login);
}
}
private String acquireRandomOfflineUser()
{
while (true)
{
int nextIdx = rnd.nextInt(userStatusByLogin.values().size());
int i = 0;
for (Map.Entry<String, AtomicBoolean> entry : userStatusByLogin.entrySet())
{
i++;
if (i >= nextIdx)
{
String login = entry.getKey();
AtomicBoolean status = entry.getValue();
if (!status.get())
{
if (status.compareAndSet(false, true))
{
return login;
}
}
}
}
}
}
private void releaseUser(String login)
{
userStatusByLogin.get(login).set(false);
}
private void sleep(long delay)
{
try
{
Thread.sleep(delay);
} catch (InterruptedException e)
{
Thread.interrupted();
}
}
}
}