Complete exercise 14.47 on page 552 Submit the Responder.java file Responder.jav
ID: 3726871 • Letter: C
Question
Complete exercise 14.47 on page 552 Submit the Responder.java file
Responder.java file:
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.util.*;
/**
* The responder class represents a response generator object.
* It is used to generate an automatic response, based on specified input.
* Input is presented to the responder as a set of words, and based on those
* words the responder will generate a String that represents the response.
*
* Internally, the reponder uses a HashMap to associate words with response
* strings and a list of default responses. If any of the input words is found
* in the HashMap, the corresponding response is returned. If none of the input
* words is recognized, one of the default responses is randomly chosen.
*
* @author David J. Barnes and Michael Kölling.
* @version 2016.02.29
*/
public class Responder
{
// Used to map key words to responses.
private HashMap responseMap;
// Default responses to use if we don't recognise a word.
private ArrayList defaultResponses;
// The name of the file containing the default responses.
private static final String FILE_OF_DEFAULT_RESPONSES = "default.txt";
private Random randomGenerator;
/**
* Construct a Responder
*/
public Responder()
{
responseMap = new HashMap<>();
defaultResponses = new ArrayList<>();
fillResponseMap();
fillDefaultResponses();
randomGenerator = new Random();
}
/**
* Generate a response from a given set of input words.
*
* @param words A set of words entered by the user
* @return A string that should be displayed as the response
*/
public String generateResponse(HashSet words)
{
Iterator it = words.iterator();
while(it.hasNext()) {
String word = it.next();
String response = responseMap.get(word);
if(response != null) {
return response;
}
}
// If we get here, none of the words from the input line was recognized.
// In this case we pick one of our default responses (what we say when
// we cannot think of anything else to say...)
return pickDefaultResponse();
}
/**
* Enter all the known keywords and their associated responses
* into our response map.
*/
private void fillResponseMap()
{
responseMap.put("crash",
"Well, it never crashes on our system. It must have something " +
"to do with your system. Tell me more about your configuration.");
responseMap.put("crashes",
"Well, it never crashes on our system. It must have something " +
"to do with your system. Tell me more about your configuration.");
responseMap.put("slow",
"I think this has to do with your hardware. Upgrading your processor " +
"should solve all performance problems. Have you got a problem with " +
"our software?");
responseMap.put("performance",
"Performance was quite adequate in all our tests. Are you running " +
"any other processes in the background?");
responseMap.put("bug",
"Well, you know, all software has some bugs. But our software engineers " +
"are working very hard to fix them. Can you describe the problem a bit " +
"further?");
responseMap.put("buggy",
"Well, you know, all software has some bugs. But our software engineers " +
"are working very hard to fix them. Can you describe the problem a bit " +
"further?");
responseMap.put("windows",
"This is a known bug to do with the Windows operating system. Please " +
"report it to Microsoft. There is nothing we can do about this.");
responseMap.put("macintosh",
"This is a known bug to do with the Mac operating system. Please " +
"report it to Apple. There is nothing we can do about this.");
responseMap.put("expensive",
"The cost of our product is quite competitive. Have you looked around " +
"and really compared our features?");
responseMap.put("installation",
"The installation is really quite straight forward. We have tons of " +
"wizards that do all the work for you. Have you read the installation " +
"instructions?");
responseMap.put("memory",
"If you read the system requirements carefully, you will see that the " +
"specified memory requirements are 1.5 giga byte. You really should " +
"upgrade your memory. Anything else you want to know?");
responseMap.put("linux",
"We take Linux support very seriously. But there are some problems. " +
"Most have to do with incompatible glibc versions. Can you be a bit " +
"more precise?");
responseMap.put("bluej",
"Ahhh, BlueJ, yes. We tried to buy out those guys long ago, but " +
"they simply won't sell... Stubborn people they are. Nothing we can " +
"do about it, I'm afraid.");
}
/**
* Build up a list of default responses from which we can pick
* if we don't know what else to say.
*/
private void fillDefaultResponses()
{
Charset charset = Charset.forName("US-ASCII");
Path path = Paths.get(FILE_OF_DEFAULT_RESPONSES);
try (BufferedReader reader = Files.newBufferedReader(path, charset)) {
String response = reader.readLine();
while(response != null) {
defaultResponses.add(response);
response = reader.readLine();
}
}
catch(FileNotFoundException e) {
System.err.println("Unable to open " + FILE_OF_DEFAULT_RESPONSES);
}
catch(IOException e) {
System.err.println("A problem was encountered reading " +
FILE_OF_DEFAULT_RESPONSES);
}
// Make sure we have at least one response.
if(defaultResponses.size() == 0) {
defaultResponses.add("Could you elaborate on that?");
}
}
/**
* Randomly select and return one of the default responses.
* @return A random default response
*/
private String pickDefaultResponse()
{
// Pick a random number for the index in the default response list.
// The number will be between 0 (inclusive) and the size of the list (exclusive).
int index = randomGenerator.nextInt(defaultResponses.size());
return defaultResponses.get(index);
}
}
Explanation / Answer
package org.apache.avro.ipc;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.UnresolvedUnionException;
import org.apache.avro.Protocol;
import org.apache.avro.Schema;
import org.apache.avro.Protocol.Message;
import org.apache.avro.util.ByteBufferInputStream;
import org.apache.avro.util.ByteBufferOutputStream;
import org.apache.avro.util.Utf8;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
/** Base class for the server side of a protocol interaction. */
public abstract class Responder {
private static final Logger LOG = LoggerFactory.getLogger(Responder.class);
private static final Schema META =
Schema.createMap(Schema.create(Schema.Type.BYTES));
private static final GenericDatumReader<Map<String,ByteBuffer>>
META_READER = new GenericDatumReader<>(META);
private static final GenericDatumWriter<Map<String,ByteBuffer>>
META_WRITER = new GenericDatumWriter<>(META);
private static final ThreadLocal<Protocol> REMOTE =
new ThreadLocal<>();
private final Map<MD5,Protocol> protocols
= new ConcurrentHashMap<>();
private final Protocol local;
private final MD5 localHash;
protected final List<RPCPlugin> rpcMetaPlugins;
protected Responder(Protocol local) {
this.local = local;
this.localHash = new MD5();
localHash.bytes(local.getMD5());
protocols.put(localHash, local);
this.rpcMetaPlugins =
new CopyOnWriteArrayList<>();
}
/** Return the remote protocol. Accesses a {@link ThreadLocal} that's set
* around calls to {@link #respond(Protocol.Message, Object)}. */
public static Protocol getRemote() { return REMOTE.get(); }
/** Return the local protocol. */
public Protocol getLocal() { return local; }
/**
* Adds a new plugin to manipulate per-call metadata. Plugins
* are executed in the order that they are added.
* @param plugin a plugin that will manipulate RPC metadata
*/
public void addRPCPlugin(RPCPlugin plugin) {
rpcMetaPlugins.add(plugin);
}
/** Called by a server to deserialize a request, compute and serialize
* a response or error. */
public List<ByteBuffer> respond(List<ByteBuffer> buffers) throws IOException {
return respond(buffers, null);
}
/** Called by a server to deserialize a request, compute and serialize a
* response or error. Transceiver is used by connection-based servers to
* track handshake status of connection. */
public List<ByteBuffer> respond(List<ByteBuffer> buffers,
Transceiver connection) throws IOException {
Decoder in = DecoderFactory.get().binaryDecoder(
new ByteBufferInputStream(buffers), null);
ByteBufferOutputStream bbo = new ByteBufferOutputStream();
BinaryEncoder out = EncoderFactory.get().binaryEncoder(bbo, null);
Exception error = null;
RPCContext context = new RPCContext();
List<ByteBuffer> payload = null;
List<ByteBuffer> handshake = null;
boolean wasConnected = connection != null && connection.isConnected();
try {
Protocol remote = handshake(in, out, connection);
out.flush();
if (remote == null) // handshake failed
return bbo.getBufferList();
handshake = bbo.getBufferList();
// read request using remote protocol specification
context.setRequestCallMeta(META_READER.read(null, in));
String messageName = in.readString(null).toString();
if (messageName.equals("")) // a handshake ping
return handshake;
Message rm = remote.getMessages().get(messageName);
if (rm == null)
throw new AvroRuntimeException("No such remote message: "+messageName);
Message m = getLocal().getMessages().get(messageName);
if (m == null)
throw new AvroRuntimeException("No message named "+messageName
+" in "+getLocal());
Object request = readRequest(rm.getRequest(), m.getRequest(), in);
context.setMessage(rm);
for (RPCPlugin plugin : rpcMetaPlugins) {
plugin.serverReceiveRequest(context);
}
// create response using local protocol specification
if ((m.isOneWay() != rm.isOneWay()) && wasConnected)
throw new AvroRuntimeException("Not both one-way: "+messageName);
Object response = null;
try {
REMOTE.set(remote);
response = respond(m, request);
context.setResponse(response);
} catch (Exception e) {
error = e;
context.setError(error);
LOG.warn("user error", e);
} finally {
REMOTE.set(null);
}
if (m.isOneWay() && wasConnected) // no response data
return null;
out.writeBoolean(error != null);
if (error == null)
writeResponse(m.getResponse(), response, out);
else
try {
writeError(m.getErrors(), error, out);
} catch (UnresolvedUnionException e) { // unexpected error
throw error;
}
} catch (Exception e) { // system error
LOG.warn("system error", e);
context.setError(e);
bbo = new ByteBufferOutputStream();
out = EncoderFactory.get().binaryEncoder(bbo, null);
out.writeBoolean(true);
writeError(Protocol.SYSTEM_ERRORS, new Utf8(e.toString()), out);
if (null == handshake) {
handshake = new ByteBufferOutputStream().getBufferList();
}
}
out.flush();
payload = bbo.getBufferList();
// Grab meta-data from plugins
context.setResponsePayload(payload);
for (RPCPlugin plugin : rpcMetaPlugins) {
plugin.serverSendResponse(context);
}
META_WRITER.write(context.responseCallMeta(), out);
out.flush();
// Prepend handshake and append payload
bbo.prepend(handshake);
bbo.append(payload);
return bbo.getBufferList();
}
private SpecificDatumWriter<HandshakeResponse> handshakeWriter =
new SpecificDatumWriter<>(HandshakeResponse.class);
private SpecificDatumReader<HandshakeRequest> handshakeReader =
new SpecificDatumReader<>(HandshakeRequest.class);
private Protocol handshake(Decoder in, Encoder out, Transceiver connection)
throws IOException {
if (connection != null && connection.isConnected())
return connection.getRemote();
HandshakeRequest request = (HandshakeRequest)handshakeReader.read(null, in);
Protocol remote = protocols.get(request.clientHash);
if (remote == null && request.clientProtocol != null) {
remote = Protocol.parse(request.clientProtocol.toString());
protocols.put(request.clientHash, remote);
}
HandshakeResponse response = new HandshakeResponse();
if (localHash.equals(request.serverHash)) {
response.match =
remote == null ? HandshakeMatch.NONE : HandshakeMatch.BOTH;
} else {
response.match =
remote == null ? HandshakeMatch.NONE : HandshakeMatch.CLIENT;
}
if (response.match != HandshakeMatch.BOTH) {
response.serverProtocol = local.toString();
response.serverHash = localHash;
}
RPCContext context = new RPCContext();
context.setHandshakeRequest(request);
context.setHandshakeResponse(response);
for (RPCPlugin plugin : rpcMetaPlugins) {
plugin.serverConnecting(context);
}
handshakeWriter.write(response, out);
if (connection != null && response.match != HandshakeMatch.NONE)
connection.setRemote(remote);
return remote;
}
/** Computes the response for a message. */
public abstract Object respond(Message message, Object request)
throws Exception;
/** Reads a request message. */
public abstract Object readRequest(Schema actual, Schema expected, Decoder in)
throws IOException;
/** Writes a response message. */
public abstract void writeResponse(Schema schema, Object response,
Encoder out) throws IOException;
/** Writes an error message. */
public abstract void writeError(Schema schema, Object error,
Encoder out) throws IOException;
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.