package events.internal; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import core.VSInternalProcess; import core.VSTask; import core.VSTaskManager; import events.VSAbstractEvent; import events.VSCopyableEvent; import events.VSRegisteredEvents; import protocols.VSAbstractProtocol; import serialize.VSSerialize; /** * The class VSProtocolEvent, this event is used if a protocol (server or * client part) of a process gets enabled or disabled, an object of this class * can be for 4 different purporses! Activation of the client protocol, * deactivation of the client protocol, activation of the server protocol, * deactivation of the server protocol. * * @author Paul C. Buetow */ public class VSProtocolEvent extends VSAbstractInternalEvent implements VSCopyableEvent { /** The protocol classname. */ private String protocolClassname; /** The event is a client protocol if true. Else it is a server protocol */ private boolean isClientProtocol; @Override public boolean isProtocolEvent() { return true; } @Override public int getEventPriority() { return PRIORITY_MEDIUM; } /** The event is a protocol activation if true. Else it is a deactivation */ private boolean isProtocolActivation; /* (non-Javadoc) * @see events.VSCopyableEvent#initCopy(events.VSAbstractEvent) */ public void initCopy(VSAbstractEvent copy) { VSProtocolEvent protocolEventCopy = (VSProtocolEvent) copy; protocolEventCopy.isClientProtocol(isClientProtocol); protocolEventCopy.isProtocolActivation(isProtocolActivation); protocolEventCopy.setProtocolClassname(protocolClassname); } /* (non-Javadoc) * @see events.VSAbstractEvent#onInit() */ public void onInit() { setClassname(getClass().toString()); } /** * Sets if it is a client protocol activation/deactivation. * * @param isClientProtocol the event is client protocol if true. the event * is a server protocol if false. */ public void isClientProtocol(boolean isClientProtocol) { this.isClientProtocol = isClientProtocol; } /** * Checks if it is a client protocol activation/deactivation. * * @return the event is client protocol if true. the event * is a server protocol if false. */ public boolean isClientProtocol() { return isClientProtocol; } /** * Sets if it is protocol activation. * * @param isProtocolActivation true, if it is a protocol activation. false, * if it is a protocol deactivation. */ public void isProtocolActivation(boolean isProtocolActivation) { this.isProtocolActivation = isProtocolActivation; } /** * Checks if it is protocol activation. * * @return true, if it is a protocol activation. false, if it is a protocol * deactivation. */ public boolean isProtocolActivation() { return isProtocolActivation; } /** * Sets the protocol classname. * * @param protocolClassname the new protocol classname */ public void setProtocolClassname(String protocolClassname) { this.protocolClassname = protocolClassname; } /** * Checks if we should schedule a protocol start task. * We should NOT schedule if the protocol is already scheduled at the current time. * This prevents duplicate execution when loading saved simulations. * * @param process the process to check * @param protocol the protocol to check for * @return true if we should schedule, false if already scheduled */ private boolean shouldScheduleProtocolStart(VSInternalProcess process, VSAbstractProtocol protocol) { // Check process-local tasks for (VSTask task : process.getTasks()) { if (task.getEvent() == protocol && task.getTaskTime() == process.getTime()) { // Protocol is already scheduled at this time return false; } } // Check global tasks VSTaskManager taskManager = process.getSimulatorCanvas().getTaskManager(); try { // Use reflection to access global tasks java.lang.reflect.Field globalTasksField = VSTaskManager.class.getDeclaredField("globalTasks"); globalTasksField.setAccessible(true); @SuppressWarnings("unchecked") java.util.Queue globalTasks = (java.util.Queue) globalTasksField.get(taskManager); for (VSTask task : globalTasks) { if (task.getEvent() == protocol && task.getTaskTime() == process.getGlobalTime()) { // Protocol is already scheduled at this time return false; } } } catch (Exception e) { // If we can't check, assume we should schedule System.err.println("Warning: Could not check for duplicate protocol tasks: " + e.getMessage()); } return true; } /* (non-Javadoc) * @see events.VSAbstractEvent#onStart() */ public void onStart() { VSInternalProcess internalProcess = (VSInternalProcess) process; VSAbstractProtocol protocol = internalProcess.getProtocolObject(protocolClassname); if (isClientProtocol) protocol.isClient(isProtocolActivation); else protocol.isServer(isProtocolActivation); StringBuffer buffer = new StringBuffer(); buffer.append(VSRegisteredEvents.getShortnameByClassname(protocolClassname)); if (buffer.length() == 0) { buffer.append(protocolClassname); } buffer.append(" "); buffer.append(isClientProtocol ? prefs.getString("lang.client") : prefs.getString("lang.server")); buffer.append(" "); buffer.append(isProtocolActivation ? prefs.getString("lang.activated") : prefs.getString("lang.deactivated")); log(buffer.toString()); // If this is an activation, schedule the protocol to start immediately // This ensures that protocols with HAS_ON_SERVER_START or HAS_ON_CLIENT_START // will have their onServerStart() or onClientStart() methods called // // However, we should NOT schedule if the protocol is already scheduled to run. // This can happen when loading from a saved simulation where both the activation // event and the resulting protocol task were saved. if (isProtocolActivation && shouldScheduleProtocolStart(internalProcess, protocol)) { // Create a task to start the protocol at the current time VSTask startTask = new VSTask(internalProcess.getTime(), internalProcess, protocol, VSTask.LOCAL); internalProcess.getSimulatorCanvas().getTaskManager().addTask(startTask); } } /* (non-Javadoc) * @see serialize.VSSerializable#serialize(serialize.VSSerialize, * java.io.ObjectOutputStream) */ public synchronized void serialize(VSSerialize serialize, ObjectOutputStream objectOutputStream) throws IOException { super.serialize(serialize, objectOutputStream); /** For later backwards compatibility, to add more stuff */ objectOutputStream.writeObject(Boolean.valueOf(false)); objectOutputStream.writeObject(protocolClassname); objectOutputStream.writeObject(Boolean.valueOf(isClientProtocol)); objectOutputStream.writeObject(Boolean.valueOf(isProtocolActivation)); /** For later backwards compatibility, to add more stuff */ objectOutputStream.writeObject(Boolean.valueOf(false)); } /* (non-Javadoc) * @see serialize.VSSerializable#deserialize(serialize.VSSerialize, * java.io.ObjectInputStream) */ public synchronized void deserialize(VSSerialize serialize, ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException { super.deserialize(serialize, objectInputStream); if (VSSerialize.DEBUG) System.out.println("Deserializing: VSProtocolEvent"); /** For later backwards compatibility, to add more stuff */ objectInputStream.readObject(); // Set protocolClassname before calling createShortname protocolClassname = (String) objectInputStream.readObject(); isClientProtocol = ((Boolean) objectInputStream.readObject()).booleanValue(); isProtocolActivation = ((Boolean) objectInputStream.readObject()).booleanValue(); // Set the event shortname using current localization this.setShortname(createShortname(null)); /** For later backwards compatibility, to add more stuff */ objectInputStream.readObject(); } protected String createShortname(String savedShortname) { // Handle case where this is called during parent deserialization // before our fields are initialized if (protocolClassname == null || prefs == null) { return savedShortname != null ? savedShortname : "Protocol Event"; } // Always use current localization strings String protocolShortname = VSRegisteredEvents.getShortnameByClassname(protocolClassname); if (protocolShortname == null) { protocolShortname = protocolClassname; } String clientServer = isClientProtocol ? prefs.getString("lang.client") : prefs.getString("lang.server"); String activateDeactivate = isProtocolActivation ? prefs.getString("lang.activated") : prefs.getString("lang.deactivated"); return protocolShortname + " " + clientServer + " " + activateDeactivate; } }