Citadel v2 & Command Pattern

When I was in charge of implementing Version 2 of Citadel I was in charge of creating groups which allowed players in the group access reinforcements.

I also introduced the Command Pattern (which was later adopted by many plugin developers to easily manage the commands from the user’s console).

First we have to create the CommandHandler:

public class CommandHandler {

	private Map<String, Command> commands = new LinkedHashMap<String, Command>();
	private Map<String, Command> identifiers = new HashMap<String, Command>();

	public void addCommand(Command command){
		this.commands.put(command.getName().toLowerCase(), command);
		for(String ident : command.getIdentifiers()){
			this.identifiers.put(ident.toLowerCase(), command);

	public boolean dispatch(CommandSender sender, String label, String[] args){
		for(int argsIncluded = args.length; argsIncluded >= 0; argsIncluded--){
			StringBuilder identifier = new StringBuilder(label);
			for(int i = 0; i < argsIncluded; i++){
				identifier.append(" ").append(args[i]);

			Command cmd = getCmdFromIdent(identifier.toString(), sender);
			if(cmd == null){
			String[] realArgs = (String[])Arrays.copyOfRange(args, argsIncluded, args.length);

				if((realArgs.length < cmd.getMinArguments()) || (realArgs.length > cmd.getMaxArguments())){
					displayCommandHelp(cmd, sender);
					return true;
				if((realArgs.length > 0) && (realArgs[0].equals("?"))){
					displayCommandHelp(cmd, sender);
					return true;

			cmd.execute(sender, realArgs);
			return true;
		return true;

	private void displayCommandHelp(Command cmd, CommandSender sender){
		sender.sendMessage(new StringBuilder().append("§cCommand:§e " ).append(cmd.getName()).toString());
		sender.sendMessage(new StringBuilder().append("§cDescription:§e " ).append(cmd.getDescription()).toString());
		sender.sendMessage(new StringBuilder().append("§cUsage:§e ").append(cmd.getUsage()).toString());

	private Command getCmdFromIdent(String ident, CommandSender executor) {
		ident = ident.toLowerCase();
			return (Command)this.identifiers.get(ident);

		for(Command cmd : this.commands.values()){
			if(cmd.isIdentifier(executor, ident)){
				return cmd;

		return null;

Then a command:

public class PasswordCommand extends PlayerCommand {

	public PasswordCommand() {
		super("Set Group Password");
        setDescription("Sets the password for a group. Set password to \"null\" to make your group not joinable");
        setUsage("/ctpassword §8<group-name> <password>");
		setIdentifiers(new String[] {"ctpassword", "ctpw"});

	public boolean execute(CommandSender sender, String[] args) {
		String groupName = args[0];
		GroupManager groupManager = Citadel.getGroupManager();
		Faction group = groupManager.getGroup(groupName);
		if(group == null){
			sendMessage(sender, ChatColor.RED, "Group doesn't exist");
			return true;
		String playerName = sender.getName();
			sendMessage(sender, ChatColor.RED, "Invalid permission to modify this group");
			return true;
		String password = args[1];
		if(password.isEmpty() || password.equals("")){
			sendMessage(sender, ChatColor.RED, "Please enter a password");
			return true;
		sendMessage(sender, ChatColor.GREEN, "Changed password for %s to \"%s\"", groupName, password);
		return true;


Notice the following:

super("Set Group Password");
        setDescription("Sets the password for a group. Set password to \"null\" to make your group not joinable");
        setUsage("/ctpassword §8<group-name> <password>");
		setIdentifiers(new String[] {"ctpassword", "ctpw"});

If there are parameters missing it will return a message from the information provided in the code above.
Notice in CommandHandler:

displayCommandHelp(cmd, sender);

Next we instantiate the commands in the singleton or main file called Citadel:

    public void registerCommands(){
    	commandHandler.addCommand(new AddModCommand());
    	commandHandler.addCommand(new AllowCommand());
    	commandHandler.addCommand(new BypassCommand());
    	commandHandler.addCommand(new CreateCommand());
    	commandHandler.addCommand(new DeleteCommand());
    	commandHandler.addCommand(new DisallowCommand());
    	commandHandler.addCommand(new FortifyCommand());
    	commandHandler.addCommand(new GroupCommand());
    	commandHandler.addCommand(new GroupsCommand());
    	commandHandler.addCommand(new InfoCommand());
    	commandHandler.addCommand(new JoinCommand());
    	commandHandler.addCommand(new LeaveCommand());
    	commandHandler.addCommand(new MaterialsCommand());
    	commandHandler.addCommand(new MembersCommand());
    	commandHandler.addCommand(new ModeratorsCommand());
    	commandHandler.addCommand(new NonReinforceableCommand());
    	commandHandler.addCommand(new OffCommand());
    	commandHandler.addCommand(new PasswordCommand());
    	commandHandler.addCommand(new PrivateCommand());
    	commandHandler.addCommand(new PublicCommand());
    	commandHandler.addCommand(new ReinforceCommand());
    	commandHandler.addCommand(new RemoveModCommand());
    	commandHandler.addCommand(new SecurableCommand());
    	commandHandler.addCommand(new StatsCommand());
    	commandHandler.addCommand(new TransferCommand());
    	commandHandler.addCommand(new VersionCommand());

Greetapp – Specification Pattern Example

Small example of the Specification pattern:

     * GET  /greets-by-user/:groupId : get all the greets by group.
     * @return the ResponseEntity with status 200 (OK) and the list of greets in body
    public Object getAllGreetsByGroup(@PathVariable Long groupId) {
        log.debug("REST request to get all Greets by user");
        List<Greet> greets = greetService.getByGang(groupId);

        Optional<Gang> optionalGang = this.gangService.getById(groupId);
        Gang gang = optionalGang.get();

        CanViewGang canViewGang = new CanViewGang(this.userService);
        if (!canViewGang.isSatisfiedBy(gang)) {
            return new ResponseEntity<>(HttpStatus.FORBIDDEN);

        CanViewGreetsByGang canViewGreetsByGang = new CanViewGreetsByGang(this.userRepository);

        List<Greet> greetsToShow = new ArrayList<Greet>();
        for (Greet greet : greets) {
            if (canViewGreetsByGang.isSatisfiedBy(greet)) {

        return greetsToShow;
public class CanViewGreetsByGang extends AbstractSpecification<Greet> {
    private User loggedInUser;

    public CanViewGreetsByGang(UserRepository userRepository) {
        Optional<String> login = SecurityUtils.getCurrentUserLogin();
        this.loggedInUser = userRepository.findOneByLogin(login.get()).get();

    public boolean isSatisfiedBy(Greet greet) {
        IsGangPublic isGangPublic = new IsGangPublic();
        IsHostOfGreet isHostOfGreet = new IsHostOfGreet(this.loggedInUser);
        IsMemberOfGang isMemberOfGang = new IsMemberOfGang(this.loggedInUser);

        boolean isGangPublicOrIsMemberOfGangBoolean = isGangPublic

        boolean isHostOfGreetBoolean = isHostOfGreet

        return isGangPublicOrIsMemberOfGangBoolean || isHostOfGreetBoolean;

A Finite State Machine in Minecraft

public String first(String text) {
return text.substring(0, 1);
@EventHandler(priority = EventPriority.HIGHEST)
public void blockPlace(BlockPlaceEvent bpe)
    // Block placed by player
    Block block = bpe.getBlock();
    // Get the blocks material relative to the block placed by the player
    Material main = block.getType();
    Material up1 = block.getRelative(BlockFace.UP, 1).getType();
    Material up2 = block.getRelative(BlockFace.UP, 2).getType();
    Material down1 = block.getRelative(BlockFace.DOWN, 1).getType();
    Material down2 = block.getRelative(BlockFace.DOWN, 2).getType();
    // Concatenate the first letters of each of the materials
    String materialFirstLetters = first(up1.toString()) + first(up2.toString()) +
                                  first(main.toString()) + first(down1.toString()) +
    // Regex pattern
    String regex = "DIJ..|I.DJ.|..IDJ";
    // Check if the first letters of the materials match the regex pattern
    if (materialFirstLetters.matches(regex))
        System.out.println("Antenna Created");

Online Book Store

For my final year project I had to build an n-tier web application from scratch using design patterns such as MVC, Command, Factory, Service, and DAO and technologies such as Java, JSP, JSTL, Tomcat, JUnit, XML, HTML/CSS, Javascript, MySQL.

Homepage. Displays featured books, latest books, newest members, and recent reviews.