Fix the commands cache and hashCode() in SmtpCommand

Motivation:
- A `hashCode` of the SmtpCommand is recalculated on each call of `hashCode()`. Cached hash code value can be just replaced with call of `name.hashCode()`.
- The commands cache don't work for strings: `SmtpCommand.valueOf("HELO")` returns a new instance.
- Field `contentExpected` is redundant and can be replaced with `equals(DATA)`.

Modifications:
- Use the `name.hashCode()` as hash code result.
- Fix a command cache: use strings as map keys.
- Replace field `contentExpected` to using `this.equals(DATA)`.
- Add unit tests.

Result:
More correct and clean code.
This commit is contained in:
Nikolay Fedorovskikh 2017-08-15 23:23:35 +05:00 committed by Norman Maurer
parent 03d89c2222
commit 0234878c4b
2 changed files with 76 additions and 45 deletions

View File

@ -29,53 +29,46 @@ import java.util.Map;
*/ */
@UnstableApi @UnstableApi
public final class SmtpCommand { public final class SmtpCommand {
public static final SmtpCommand EHLO = new SmtpCommand(AsciiString.cached("EHLO"), false); public static final SmtpCommand EHLO = new SmtpCommand(AsciiString.cached("EHLO"));
public static final SmtpCommand HELO = new SmtpCommand(AsciiString.cached("HELO"), false); public static final SmtpCommand HELO = new SmtpCommand(AsciiString.cached("HELO"));
public static final SmtpCommand MAIL = new SmtpCommand(AsciiString.cached("MAIL"), false); public static final SmtpCommand MAIL = new SmtpCommand(AsciiString.cached("MAIL"));
public static final SmtpCommand RCPT = new SmtpCommand(AsciiString.cached("RCPT"), false); public static final SmtpCommand RCPT = new SmtpCommand(AsciiString.cached("RCPT"));
public static final SmtpCommand DATA = new SmtpCommand(AsciiString.cached("DATA"), true); public static final SmtpCommand DATA = new SmtpCommand(AsciiString.cached("DATA"));
public static final SmtpCommand NOOP = new SmtpCommand(AsciiString.cached("NOOP"), false); public static final SmtpCommand NOOP = new SmtpCommand(AsciiString.cached("NOOP"));
public static final SmtpCommand RSET = new SmtpCommand(AsciiString.cached("RSET"), false); public static final SmtpCommand RSET = new SmtpCommand(AsciiString.cached("RSET"));
public static final SmtpCommand EXPN = new SmtpCommand(AsciiString.cached("EXPN"), false); public static final SmtpCommand EXPN = new SmtpCommand(AsciiString.cached("EXPN"));
public static final SmtpCommand VRFY = new SmtpCommand(AsciiString.cached("VRFY"), false); public static final SmtpCommand VRFY = new SmtpCommand(AsciiString.cached("VRFY"));
public static final SmtpCommand HELP = new SmtpCommand(AsciiString.cached("HELP"), false); public static final SmtpCommand HELP = new SmtpCommand(AsciiString.cached("HELP"));
public static final SmtpCommand QUIT = new SmtpCommand(AsciiString.cached("QUIT"), false); public static final SmtpCommand QUIT = new SmtpCommand(AsciiString.cached("QUIT"));
private static final CharSequence DATA_CMD = AsciiString.cached("DATA"); private static final Map<String, SmtpCommand> COMMANDS = new HashMap<String, SmtpCommand>();
private static final Map<CharSequence, SmtpCommand> COMMANDS = new HashMap<CharSequence, SmtpCommand>();
static { static {
COMMANDS.put(EHLO.name(), EHLO); COMMANDS.put(EHLO.name().toString(), EHLO);
COMMANDS.put(HELO.name(), HELO); COMMANDS.put(HELO.name().toString(), HELO);
COMMANDS.put(MAIL.name(), MAIL); COMMANDS.put(MAIL.name().toString(), MAIL);
COMMANDS.put(RCPT.name(), RCPT); COMMANDS.put(RCPT.name().toString(), RCPT);
COMMANDS.put(DATA.name(), DATA); COMMANDS.put(DATA.name().toString(), DATA);
COMMANDS.put(NOOP.name(), NOOP); COMMANDS.put(NOOP.name().toString(), NOOP);
COMMANDS.put(RSET.name(), RSET); COMMANDS.put(RSET.name().toString(), RSET);
COMMANDS.put(EXPN.name(), EXPN); COMMANDS.put(EXPN.name().toString(), EXPN);
COMMANDS.put(VRFY.name(), VRFY); COMMANDS.put(VRFY.name().toString(), VRFY);
COMMANDS.put(HELP.name(), HELP); COMMANDS.put(HELP.name().toString(), HELP);
COMMANDS.put(QUIT.name(), QUIT); COMMANDS.put(QUIT.name().toString(), QUIT);
} }
/** /**
* Returns the {@link SmtpCommand} for the given command name. * Returns the {@link SmtpCommand} for the given command name.
*/ */
public static SmtpCommand valueOf(CharSequence commandName) { public static SmtpCommand valueOf(CharSequence commandName) {
SmtpCommand command = COMMANDS.get(commandName); ObjectUtil.checkNotNull(commandName, "commandName");
if (command != null) { SmtpCommand command = COMMANDS.get(commandName.toString());
return command; return command != null ? command : new SmtpCommand(AsciiString.of(commandName));
}
return new SmtpCommand(AsciiString.of(ObjectUtil.checkNotNull(commandName, "commandName")),
AsciiString.contentEqualsIgnoreCase(commandName, DATA_CMD));
} }
private final AsciiString name; private final AsciiString name;
private final boolean contentExpected;
private int hashCode;
private SmtpCommand(AsciiString name, boolean contentExpected) { private SmtpCommand(AsciiString name) {
this.name = name; this.name = name;
this.contentExpected = contentExpected;
} }
/** /**
@ -86,19 +79,16 @@ public final class SmtpCommand {
} }
void encode(ByteBuf buffer) { void encode(ByteBuf buffer) {
ByteBufUtil.writeAscii(buffer, name()); ByteBufUtil.writeAscii(buffer, name);
} }
boolean isContentExpected() { boolean isContentExpected() {
return contentExpected; return this.equals(DATA);
} }
@Override @Override
public int hashCode() { public int hashCode() {
if (hashCode != -1) { return name.hashCode();
hashCode = AsciiString.hashCode(name);
}
return hashCode;
} }
@Override @Override
@ -114,10 +104,6 @@ public final class SmtpCommand {
@Override @Override
public String toString() { public String toString() {
return "SmtpCommand{" + return "SmtpCommand{name=" + name + '}';
"name=" + name +
", contentExpected=" + contentExpected +
", hashCode=" + hashCode +
'}';
} }
} }

View File

@ -0,0 +1,45 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you 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 io.netty.handler.codec.smtp;
import org.junit.Test;
import static org.junit.Assert.*;
public class SmtpCommandTest {
@Test
public void getCommandFromCache() {
assertSame(SmtpCommand.DATA, SmtpCommand.valueOf("DATA"));
assertSame(SmtpCommand.EHLO, SmtpCommand.valueOf("EHLO"));
assertNotSame(SmtpCommand.EHLO, SmtpCommand.valueOf("ehlo"));
}
@Test
public void equalsIgnoreCase() {
assertEquals(SmtpCommand.MAIL, SmtpCommand.valueOf("mail"));
assertEquals(SmtpCommand.valueOf("test"), SmtpCommand.valueOf("TEST"));
}
@Test
public void isContentExpected() {
assertTrue(SmtpCommand.valueOf("DATA").isContentExpected());
assertTrue(SmtpCommand.valueOf("data").isContentExpected());
assertFalse(SmtpCommand.HELO.isContentExpected());
assertFalse(SmtpCommand.HELP.isContentExpected());
assertFalse(SmtpCommand.valueOf("DATA2").isContentExpected());
}
}