/*
* Copyright 2013 Pavel Stastny <pavel.stastny at gmail.com>.
*
* 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.aplikator.server.processes.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.aplikator.server.processes.Process;
import org.aplikator.server.processes.ProcessManager;
import org.aplikator.server.processes.impl.processes.ipc.IPCChanelFactory;
import org.aplikator.server.processes.impl.processes.ipc.IPCChannel;
import org.aplikator.server.processes.impl.processes.ipc.IPCMessage;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @author Pavel Stastny <pavel.stastny at gmail.com>
*/
public class ProcessManagerImpl extends ProcessManager {
public static final Logger LOGGER = Logger.getLogger(Logger.class.getName());
private static final int SCHEDULING_INTERVAL = 2000;
private static final int POLL_INTERVAL = 200;
private Map<String, Process> registeredProcesses = new HashMap<String, Process>();
private ScheduledExecutorService executorService;
private ScheduledExecutorService pollProcessBusService;
// scheduled processes
private List<ProcessScheduling> scheduled = new ArrayList<ProcessScheduling>();
boolean started = false;
final Object lock = new Object();
public ProcessManagerImpl(String appname) {
LOGGER.info("initializing manager '" + appname + "'");
this.executorService = Executors.newScheduledThreadPool(1);
this.executorService.schedule(new ProcessCheck(), SCHEDULING_INTERVAL, TimeUnit.MILLISECONDS);
this.pollProcessBusService = Executors.newScheduledThreadPool(1);
this.pollProcessBusService.schedule(new ProcessMessagePoll(appname), POLL_INTERVAL, TimeUnit.MILLISECONDS);
}
@Override
public List<Process> getProcesses() {
Set<String> keySet = this.registeredProcesses.keySet();
List<Process> processes = new ArrayList<Process>();
for (String key : keySet) {
processes.add(this.registeredProcesses.get(key));
}
return processes;
}
@Override
public void registerProcess(Process process) {
this.registeredProcesses.put(process.getIdentifier(), process);
}
@Override
public void deregisterProcess(Process process) {
this.registeredProcesses.remove(process.getIdentifier());
}
@Override
public void startScheduling() {
synchronized (lock) {
if (!this.started) {
executorService.schedule(new ProcessCheck(), SCHEDULING_INTERVAL, TimeUnit.MILLISECONDS);
this.started = true;
}
}
}
@Override
public void stopScheduling() {
synchronized (lock) {
if (!this.executorService.isShutdown() && (!this.executorService.isTerminated())) {
this.executorService.shutdown();
}
}
}
@Override
public void shutDown() {
this.executorService.shutdown();
this.pollProcessBusService.shutdown();
}
@Override
public void schedule(Process process, Date schedulingTime) {
synchronized (lock) {
ProcessScheduling psch = new ProcessScheduling(process, schedulingTime);
this.scheduled.add(psch);
Collections.sort(this.scheduled);
}
}
@Override
public Process lookUpProcess(String ident) {
return this.registeredProcesses.get(ident);
}
class ProcessMessagePoll implements Runnable {
private String appname;
public ProcessMessagePoll(String appname) {
this.appname = appname;
}
@Override
public void run() {
try {
IPCChannel channel = IPCChanelFactory.createFactory().createChannel(this.appname);
IPCMessage mess = channel.receiveMessage("1");
if (mess != null) {
processMessage(mess);
}
pollProcessBusService.schedule(new ProcessMessagePoll(appname), POLL_INTERVAL, TimeUnit.MILLISECONDS);
} catch (ClassNotFoundException ex) {
Logger.getLogger(ProcessManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(ProcessManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(ProcessManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ProcessManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (JSONException ex) {
Logger.getLogger(ProcessManagerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void processMessage(IPCMessage mess) throws JSONException {
System.out.println("processing message :" + mess);
String body = mess.getBody();
JSONObject jsonObj = new JSONObject(body);
String address = mess.getSourceAddress();
Process process = registeredProcesses.get(address);
if (process != null) {
process.updateProcessIntrnalState(jsonObj);
}
}
}
class ProcessCheck implements Runnable {
@Override
public void run() {
LOGGER.info("scheduling cycle");
ProcessScheduling top = scheduled.get(0);
Date d = new Date();
if (d.after(top.getSchedulingTime())) {
Process execProcess = scheduled.remove(0).getProcess();
try {
execProcess.startMe();
} catch (Throwable e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
//scheduling next run
executorService.schedule(new ProcessCheck(), SCHEDULING_INTERVAL, TimeUnit.MILLISECONDS);
}
}
}
class ProcessScheduling implements Comparable<ProcessScheduling> {
private Process process;
private Date schedulingTime;
public ProcessScheduling(Process process, Date schedulingTime) {
this.process = process;
this.schedulingTime = schedulingTime;
}
public Date getSchedulingTime() {
return schedulingTime;
}
public Process getProcess() {
return process;
}
@Override
public int compareTo(ProcessScheduling o) {
return this.schedulingTime.compareTo(o.getSchedulingTime());
}
}
}