1 package cz.cuni.amis.pogamut.base.communication.command.impl;
2
3 import java.io.PrintWriter;
4 import java.io.Writer;
5 import java.util.Collection;
6 import java.util.logging.Level;
7
8 import javax.management.MBeanServer;
9 import javax.management.ObjectName;
10
11 import com.google.inject.Inject;
12
13 import cz.cuni.amis.pogamut.base.agent.jmx.IJMXEnabled;
14 import cz.cuni.amis.pogamut.base.communication.command.IAct;
15 import cz.cuni.amis.pogamut.base.communication.command.ICommandListener;
16 import cz.cuni.amis.pogamut.base.communication.command.ICommandSerializer;
17 import cz.cuni.amis.pogamut.base.communication.connection.IWorldWriterProvider;
18 import cz.cuni.amis.pogamut.base.communication.exception.CommunicationException;
19 import cz.cuni.amis.pogamut.base.communication.messages.CommandMessage;
20 import cz.cuni.amis.pogamut.base.component.IComponent;
21 import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
22 import cz.cuni.amis.pogamut.base.component.controller.ComponentControlHelper;
23 import cz.cuni.amis.pogamut.base.component.controller.ComponentController;
24 import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencyType;
25 import cz.cuni.amis.pogamut.base.component.controller.IComponentControlHelper;
26 import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
27 import cz.cuni.amis.pogamut.base.utils.jmx.PogamutJMX;
28 import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
29 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
30 import cz.cuni.amis.utils.ClassUtils;
31 import cz.cuni.amis.utils.exception.PogamutJMXException;
32 import cz.cuni.amis.utils.listener.IListener;
33 import cz.cuni.amis.utils.listener.Listeners;
34 import cz.cuni.amis.utils.listener.ListenersMap;
35 import cz.cuni.amis.utils.token.Token;
36 import cz.cuni.amis.utils.token.Tokens;
37
38
39
40
41
42
43
44
45 @AgentScoped
46 public final class Act implements IComponent, IAct, IJMXEnabled {
47
48 public static final Token COMPONENT_ID = Tokens.get("Act");
49
50
51
52
53 public static final String DEFAULT_LINE_END = "\r\n";
54
55 private static class CommandMessageListenerNotifier implements Listeners.ListenerNotifier<IListener> {
56
57 private CommandMessage msg;
58
59 public void setMessage(CommandMessage msg) {
60 this.msg = msg;
61 }
62
63 @Override
64 public void notify(IListener listener) {
65 listener.notify(msg);
66 }
67
68 @Override
69 public Object getEvent() {
70 return msg;
71 }
72 }
73
74 private CommandMessageListenerNotifier notifier = new CommandMessageListenerNotifier();
75
76 private IWorldWriterProvider writerProvider;
77
78 private Writer writer;
79
80 private PrintWriter printWriter;
81
82 private ICommandSerializer<String> serializer;
83
84 private final LogCategory log;
85
86 private IComponentBus eventBus;
87
88 private ComponentController controller;
89
90 private ListenersMap<Class> listeners = new ListenersMap<Class>();
91
92 @Inject
93 public Act(IWorldWriterProvider writerProvider, ICommandSerializer serializer, IComponentBus eventBus, IAgentLogger logger) {
94 this.log = logger.getCategory(getComponentId().getToken());
95 this.listeners.setLog(log, "Listeners");
96
97 this.writerProvider = writerProvider;
98 this.serializer = serializer;
99 this.writer = null;
100
101 this.eventBus = eventBus;
102 this.controller = new ComponentController(this, control, eventBus, log, ComponentDependencyType.STARTS_AFTER, writerProvider);
103 }
104
105 private IComponentControlHelper control = new ComponentControlHelper() {
106
107 @Override
108 public void stop() {
109 writer = null;
110 printWriter = null;
111 }
112
113 @Override
114 public void startPaused() {
115 start();
116 };
117
118 @Override
119 public void start() {
120 if (log.isLoggable(Level.FINE)) log.fine("Getting writer from " + writerProvider + ".");
121 writer = writerProvider.getWriter();
122 if (writer == null) throw new CommunicationException("Can't get writer, " + writerProvider + ".getWriter() has returned null.", log, this);
123 printWriter = new PrintWriter(writer);
124 }
125
126 @Override
127 public void kill() {
128 writer = null;
129 printWriter = null;
130 }
131
132 @Override
133 public void reset() {
134 writer = null;
135 printWriter = null;
136 }
137
138 };
139
140 @Override
141 public Token getComponentId() {
142 return COMPONENT_ID;
143 }
144
145 public LogCategory getLog() {
146 return log;
147 }
148
149
150
151
152 protected void sendCommand(CommandMessage command) {
153 printWriter.print(serializer.serialize(command) + DEFAULT_LINE_END);
154 printWriter.flush();
155 }
156
157
158
159
160
161
162
163 public synchronized void act(CommandMessage command) {
164 if (!controller.isRunning()) {
165 if (log.isLoggable(Level.WARNING)) log.warning("Not running, can't send " + command);
166 return;
167 }
168 if (log.isLoggable(Level.FINE)) log.fine("Sending: " + command);
169 notifier.setMessage(command);
170 Collection<Class> commandClasses = ClassUtils.getSubclasses(command.getClass());
171 for (Class cls : commandClasses) {
172 listeners.notify(cls, notifier);
173 }
174 sendCommand(command);
175 }
176
177 @Override
178 public void addCommandListener(Class commandClass, ICommandListener listener) {
179 listeners.add(commandClass, listener);
180 }
181
182 @Override
183 public boolean isCommandListening(Class commandClass, ICommandListener listener) {
184 return listeners.isListening(commandClass, listener);
185 }
186
187 @Override
188 public void removeCommandListener(Class commandClass, ICommandListener listener) {
189 listeners.remove(commandClass, listener);
190 }
191
192 @Override
193 public void enableJMX(MBeanServer mBeanServer, ObjectName parent) {
194 try {
195 mBeanServer.registerMBean(this, PogamutJMX.getObjectName(parent, PogamutJMX.ACT_NAME));
196 } catch (Exception ex) {
197 throw new PogamutJMXException(ex, this);
198 }
199 }
200
201 @Override
202 public String toString() {
203 return "Act[serializer=" + serializer + "]";
204 }
205
206 }