View Javadoc

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   * TODO!
40   * <p><p>
41   * Ignores {@link IComponentControlHelper#startPaused()}, performs {@link IComponentControlHelper#start()} in both start cases.
42   *  
43   * @author Jimmy
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  	 * Default termination of commands.
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 	 * Provides the implementation how to send 'command' through 'this.writer'. 
151 	 */
152 	protected void sendCommand(CommandMessage command) {
153 		printWriter.print(serializer.serialize(command) + DEFAULT_LINE_END);
154 		printWriter.flush();
155 	}
156 	
157 	/**
158 	 * Sends command through the writer.
159 	 * 
160 	 * @param command
161 	 * @throws CommunicationException
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 		
170 		//log.warning("Sending: " + command);
171 		
172 		notifier.setMessage(command);
173 		Collection<Class> commandClasses = ClassUtils.getSubclasses(command.getClass());
174 		for (Class cls : commandClasses) {
175 			listeners.notify(cls, notifier);
176 		}
177 		sendCommand(command);
178 	}
179 	
180 	@Override
181 	public void addCommandListener(Class commandClass, ICommandListener listener) {
182 		listeners.add(commandClass, listener);
183 	}
184 
185 	@Override
186 	public boolean isCommandListening(Class commandClass, ICommandListener listener) {
187 		return listeners.isListening(commandClass, listener);
188 	}
189 	
190 	@Override
191 	public void removeCommandListener(Class commandClass, ICommandListener listener) {
192 		listeners.remove(commandClass, listener);
193 	}
194 	
195 	@Override
196     public void enableJMX(MBeanServer mBeanServer, ObjectName parent) {
197         try {
198             mBeanServer.registerMBean(this, PogamutJMX.getObjectName(parent, PogamutJMX.ACT_NAME));
199         } catch (Exception ex) {
200             throw new PogamutJMXException(ex, this);
201         }
202     }
203 	
204 	@Override
205 	public String toString() {
206 		return "Act[serializer=" + serializer + "]";
207 	}
208 
209 }